<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Requests\Batches\StoreBatchRequest;
use App\Http\Requests\Batches\UpdateBatchRequest;
use App\Models\Batch;
use App\Models\BatchKpiSnapshot;
use App\Models\Tank;
use App\Support\BatchKpiSnapshotService;
use App\Support\FeedingRecommendationEngine;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class BatchController extends Controller
{
    private function enrichBatch(Batch $batch): Batch
    {
        if ((string) $batch->status === 'active') {
            $batch->setAttribute('feeding_recommendation', FeedingRecommendationEngine::recommendForBatch($batch));
        } else {
            $batch->setAttribute('feeding_recommendation', null);
        }

        return $batch;
    }

    private function biomassKgFromPayload(array $payload, ?Batch $current = null): int
    {
        $currentFishCount = $current ? $current->fish_count_current : null;
        $currentAvgWeightG = $current ? $current->avg_weight_current_g : null;

        $fishCount = max(0, (int) ($payload['fish_count_current'] ?? $currentFishCount ?? $payload['fish_count_initial'] ?? 0));
        $avgWeightG = max(0.0, (float) ($payload['avg_weight_current_g'] ?? $currentAvgWeightG ?? $payload['avg_weight_initial_g'] ?? 0));

        return (int) round(($fishCount * $avgWeightG) / 1000);
    }

    /**
     * Display a listing of the resource.
     */
    public function index(): JsonResponse
    {
        $userId = (int) auth('api')->id();
        $batches = Batch::query()->with('tank')->where('user_id', $userId)->latest()->get();

        return $this->success($batches->map(function (Batch $batch) {
            return $this->enrichBatch($batch);
        }), 'Batches list');
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(StoreBatchRequest $request): JsonResponse
    {
        $userId = (int) auth('api')->id();
        $payload = $request->validated();

        $tankId = (int) ($payload['tank_id'] ?? 0);
        $tank = Tank::query()->where('user_id', $userId)->find($tankId);
        if (! $tank) {
            return $this->error('Tank not found', null, 404);
        }

        if (($payload['status'] ?? 'active') === 'active') {
            $hasActive = Batch::query()
                ->where('user_id', $userId)
                ->where('tank_id', $tankId)
                ->where('status', 'active')
                ->exists();

            if ($hasActive) {
                return $this->error('There is already an active batch for this tank', null, 422);
            }
        }

        $payload['biomass_current_kg'] = $this->biomassKgFromPayload($payload);
        $batch = Batch::create(array_merge($payload, ['user_id' => $userId]));
        BatchKpiSnapshotService::syncBatch($batch->load('tank'));

        return $this->success($this->enrichBatch($batch->load('tank')), 'Batch created', 201);
    }

    /**
     * Display the specified resource.
     */
    public function show(int $id): JsonResponse
    {
        $userId = (int) auth('api')->id();
        $batch = Batch::query()->with('tank')->where('user_id', $userId)->find($id);

        if (! $batch) {
            return $this->error('Batch not found', null, 404);
        }

        return $this->success($this->enrichBatch($batch), 'Batch details');
    }

    public function feedingRecommendation(Request $request, int $id): JsonResponse
    {
        $userId = (int) auth('api')->id();
        $batch = Batch::query()->with('tank')->where('user_id', $userId)->find($id);

        if (! $batch) {
            return $this->error('Batch not found', null, 404);
        }

        $date = $request->query('date');
        $recommendation = FeedingRecommendationEngine::recommendForBatch(
            $batch,
            is_string($date) && $date !== '' ? $date : null
        );

        return $this->success($recommendation, 'Batch feeding recommendation');
    }

    public function closureEvaluation(int $id): JsonResponse
    {
        $userId = (int) auth('api')->id();
        $batch = Batch::query()->with('tank')->where('user_id', $userId)->find($id);

        if (! $batch) {
            return $this->error('Batch not found', null, 404);
        }

        $snapshot = BatchKpiSnapshotService::syncBatch($batch->load('tank'));
        $thresholds = $this->resolveClosureThresholds(request());

        return $this->success($this->buildClosureEvaluationPayload($batch, $snapshot, $thresholds), 'Batch closure evaluation');
    }

    public function closeCycle(Request $request, int $id): JsonResponse
    {
        $userId = (int) auth('api')->id();
        $batch = Batch::query()->with('tank')->where('user_id', $userId)->find($id);

        if (! $batch) {
            return $this->error('Batch not found', null, 404);
        }

        $data = $request->validate([
            'force' => ['sometimes', 'boolean'],
            'ended_at' => ['sometimes', 'nullable', 'date'],
        ]);

        $snapshot = BatchKpiSnapshotService::syncBatch($batch->load('tank'));
        $thresholds = $this->resolveClosureThresholds($request);
        $evaluation = $this->buildClosureEvaluationPayload($batch, $snapshot, $thresholds);
        $force = (bool) ($data['force'] ?? false);
        $recommendedStatus = (string) ($evaluation['recommended_status'] ?? 'active');

        if (! $force && $recommendedStatus === 'active') {
            return $this->error('Batch does not meet closure thresholds yet', $evaluation, 422);
        }

        $targetStatus = $force ? 'closed' : $recommendedStatus;
        $endedAt = $data['ended_at'] ?? ($batch->ended_at ? $batch->ended_at->toDateString() : now()->toDateString());

        $batch->status = $targetStatus;
        $batch->ended_at = $targetStatus === 'active' ? null : $endedAt;
        $batch->save();

        $snapshot = BatchKpiSnapshotService::syncBatch($batch->fresh()->load('tank'));

        return $this->success([
            'batch' => $this->enrichBatch($batch->fresh()->load('tank')),
            'evaluation' => $this->buildClosureEvaluationPayload($batch->fresh(), $snapshot, $thresholds),
        ], 'Batch cycle closure applied');
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(UpdateBatchRequest $request, int $id): JsonResponse
    {
        $userId = (int) auth('api')->id();
        $batch = Batch::query()->where('user_id', $userId)->find($id);

        if (! $batch) {
            return $this->error('Batch not found', null, 404);
        }

        $payload = $request->validated();
        if (array_key_exists('tank_id', $payload)) {
            $tankId = (int) ($payload['tank_id'] ?? 0);
            $tank = Tank::query()->where('user_id', $userId)->find($tankId);
            if (! $tank) {
                return $this->error('Tank not found', null, 404);
            }
        }

        $targetTankId = (int) ($payload['tank_id'] ?? $batch->tank_id);
        $targetStatus = (string) ($payload['status'] ?? $batch->status);
        if ($targetStatus === 'active') {
            $hasActive = Batch::query()
                ->where('user_id', $userId)
                ->where('tank_id', $targetTankId)
                ->where('status', 'active')
                ->where('id', '!=', $batch->id)
                ->exists();

            if ($hasActive) {
                return $this->error('There is already an active batch for this tank', null, 422);
            }
        }

        $payload['biomass_current_kg'] = $this->biomassKgFromPayload($payload, $batch);
        $batch->update($payload);
        BatchKpiSnapshotService::syncBatch($batch->load('tank'));

        return $this->success($this->enrichBatch($batch->load('tank')), 'Batch updated');
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(int $id): JsonResponse
    {
        $userId = (int) auth('api')->id();
        $batch = Batch::query()->where('user_id', $userId)->find($id);

        if (! $batch) {
            return $this->error('Batch not found', null, 404);
        }

        $batch->delete();

        return $this->success(null, 'Batch deleted');
    }

    private function buildClosureEvaluationPayload(Batch $batch, ?BatchKpiSnapshot $snapshot, array $thresholds = []): array
    {
        $thresholds = array_merge([
            'harvest_completion_pct' => 95.0,
            'residual_biomass_kg_max' => 1.0,
            'residual_live_fish_max' => 0.0,
            'sales_realization_pct' => 90.0,
            'cash_recovery_pct' => 90.0,
        ], $thresholds);
        $fishAlive = max(0, (int) ($snapshot ? ($snapshot->fish_alive ?? 0) : ($batch->fish_count_current ?? 0)));
        $biomassKg = max(0.0, (float) ($snapshot ? ($snapshot->biomass_kg ?? 0) : ($batch->biomass_current_kg ?? 0)));
        $harvestCompletionPct = $snapshot ? (float) ($snapshot->harvest_completion_pct ?? 0) : 0.0;
        $salesRealizationPct = $snapshot ? (float) ($snapshot->sales_realization_pct ?? 0) : 0.0;
        $cashRecoveryPct = $snapshot ? (float) ($snapshot->cash_recovery_pct ?? 0) : 0.0;
        $targetProgressPct = $snapshot ? (float) ($snapshot->target_progress_pct ?? 0) : 0.0;
        $netCashflowCrc = $snapshot ? (float) ($snapshot->net_cashflow_crc ?? 0) : 0.0;
        $realizedRevenueCrc = $snapshot ? (float) ($snapshot->realized_revenue_crc ?? 0) : 0.0;
        $totalCostCrc = $snapshot ? (float) ($snapshot->total_cost_crc ?? 0) : 0.0;

        $rules = [
            [
                'key' => 'harvest_completion',
                'label' => 'Harvest completion >= 95%',
                'passed' => $harvestCompletionPct >= (float) $thresholds['harvest_completion_pct'],
                'value' => round($harvestCompletionPct, 2),
                'target' => (float) $thresholds['harvest_completion_pct'],
            ],
            [
                'key' => 'residual_live_fish',
                'label' => 'Residual live fish <= 0',
                'passed' => $fishAlive <= (int) round((float) $thresholds['residual_live_fish_max']),
                'value' => $fishAlive,
                'target' => (float) $thresholds['residual_live_fish_max'],
            ],
            [
                'key' => 'residual_biomass',
                'label' => 'Residual biomass <= 1 kg',
                'passed' => $biomassKg <= (float) $thresholds['residual_biomass_kg_max'],
                'value' => round($biomassKg, 2),
                'target' => (float) $thresholds['residual_biomass_kg_max'],
            ],
            [
                'key' => 'sales_realization',
                'label' => 'Sales realization >= 90%',
                'passed' => $salesRealizationPct >= (float) $thresholds['sales_realization_pct'],
                'value' => round($salesRealizationPct, 2),
                'target' => (float) $thresholds['sales_realization_pct'],
            ],
            [
                'key' => 'cash_recovery',
                'label' => 'Cash recovery >= 90%',
                'passed' => $cashRecoveryPct >= (float) $thresholds['cash_recovery_pct'],
                'value' => round($cashRecoveryPct, 2),
                'target' => (float) $thresholds['cash_recovery_pct'],
            ],
        ];

        $operationalReady = collect($rules)
            ->whereIn('key', ['harvest_completion', 'residual_live_fish', 'residual_biomass'])
            ->contains(fn ($rule) => (bool) ($rule['passed'] ?? false));

        $financialReady = collect($rules)
            ->whereIn('key', ['sales_realization', 'cash_recovery'])
            ->every(fn ($rule) => (bool) ($rule['passed'] ?? false))
            || ($realizedRevenueCrc > 0 && $netCashflowCrc >= 0);

        $recommendedStatus = 'active';
        if ($operationalReady && $financialReady) {
            $recommendedStatus = 'closed';
        } elseif ($operationalReady || (string) $batch->status === 'closing') {
            $recommendedStatus = 'closing';
        }

        return [
            'batch_id' => (int) $batch->id,
            'current_status' => (string) ($batch->status ?? 'active'),
            'recommended_status' => $recommendedStatus,
            'operational_ready' => $operationalReady,
            'financial_ready' => $financialReady,
            'closure_ready' => $recommendedStatus !== 'active',
            'metrics' => [
                'fish_alive' => $fishAlive,
                'biomass_kg' => round($biomassKg, 2),
                'harvest_completion_pct' => round($harvestCompletionPct, 2),
                'sales_realization_pct' => round($salesRealizationPct, 2),
                'cash_recovery_pct' => round($cashRecoveryPct, 2),
                'target_progress_pct' => round($targetProgressPct, 2),
                'net_cashflow_crc' => round($netCashflowCrc, 2),
                'realized_revenue_crc' => round($realizedRevenueCrc, 2),
                'total_cost_crc' => round($totalCostCrc, 2),
            ],
            'thresholds' => [
                'harvest_completion_pct' => (float) $thresholds['harvest_completion_pct'],
                'residual_biomass_kg_max' => (float) $thresholds['residual_biomass_kg_max'],
                'residual_live_fish_max' => (float) $thresholds['residual_live_fish_max'],
                'sales_realization_pct' => (float) $thresholds['sales_realization_pct'],
                'cash_recovery_pct' => (float) $thresholds['cash_recovery_pct'],
            ],
            'rules' => $rules,
            'notes' => [
                $operationalReady
                    ? 'Operationally the cycle can leave active production.'
                    : 'Operational thresholds still suggest the lot should remain active.',
                $financialReady
                    ? 'Financial closure thresholds are satisfied.'
                    : 'Financial closure still has pending recovery/realization thresholds.',
            ],
        ];
    }

    private function resolveClosureThresholds(Request $request): array
    {
        return [
            'harvest_completion_pct' => max(0.0, min(100.0, (float) $request->input('harvest_completion_pct', 95))),
            'residual_biomass_kg_max' => max(0.0, (float) $request->input('residual_biomass_kg_max', 1)),
            'residual_live_fish_max' => max(0.0, (float) $request->input('residual_live_fish_max', 0)),
            'sales_realization_pct' => max(0.0, min(100.0, (float) $request->input('sales_realization_pct', 90))),
            'cash_recovery_pct' => max(0.0, min(100.0, (float) $request->input('cash_recovery_pct', 90))),
        ];
    }
}
