<?php

namespace App\Services;

use App\Models\Cattle;
use App\Models\FatteningLotAnimal;
use App\Models\MaterialExpense;
use App\Models\WeightRecord;
use Carbon\Carbon;

class CattleLifecycleSummaryService
{
    /**
     * Resumen para baja: engorda, alimento asignado y ganancia de peso en el ciclo actual.
     *
     * @return array{
     *   current_fattening_lot: string|null,
     *   fattening_stints: list<array<string, mixed>>,
     *   total_days_in_fattening: int,
     *   total_allocated_feed_cost: float,
     *   current_stint_weight_gain_kg: float|null,
     *   lifetime_weight_gain_kg: float|null
     * }
     */
    public function forDeactivation(Cattle $cattle, float $exitWeightKg, Carbon $exitDate): array
    {
        $cattle->loadMissing(['activeFatteningLotAssignment.fatteningLot', 'fatteningLotAssignments.fatteningLot']);

        $stints = [];
        $totalDays = 0;
        $totalFeed = 0.0;
        $currentGain = null;

        foreach ($cattle->fatteningLotAssignments->sortBy('entry_date') as $assignment) {
            $end = $assignment->exit_date ?? $exitDate;
            if ($end->lt($assignment->entry_date)) {
                continue;
            }

            $days = max(1, $assignment->entry_date->diffInDays($end));
            $exitForStint = $assignment->exit_weight_kg !== null
                ? (float) $assignment->exit_weight_kg
                : ($assignment->removed_at === null || $assignment->id === $cattle->activeFatteningLotAssignment?->id
                    ? $exitWeightKg
                    : null);

            $gain = $exitForStint !== null
                ? round($exitForStint - (float) $assignment->entry_weight_kg, 2)
                : null;

            $allocatedFeed = $this->allocateFeedCost($assignment, $assignment->entry_date, $end);

            $stint = [
                'lot_id' => $assignment->fattening_lot_id,
                'lot_name' => $assignment->fatteningLot?->name,
                'entry_date' => $assignment->entry_date->toDateString(),
                'exit_date' => $end->toDateString(),
                'days_in_confinement' => $days,
                'entry_weight_kg' => (float) $assignment->entry_weight_kg,
                'exit_weight_kg' => $exitForStint,
                'weight_gain_kg' => $gain,
                'allocated_feed_cost' => $allocatedFeed,
            ];

            $stints[] = $stint;
            $totalDays += $days;
            $totalFeed += $allocatedFeed;

            if ($assignment->id === $cattle->activeFatteningLotAssignment?->id) {
                $currentGain = $gain;
            }
        }

        return [
            'current_fattening_lot' => $cattle->activeFatteningLotAssignment?->fatteningLot?->name,
            'fattening_stints' => $stints,
            'total_days_in_fattening' => $totalDays,
            'total_allocated_feed_cost' => $this->totalAllocatedFeedCost($cattle, $exitDate),
            'current_stint_weight_gain_kg' => $currentGain,
            'lifetime_weight_gain_kg' => $this->lifetimeWeightGain($cattle, $exitWeightKg),
        ];
    }

    public function totalAllocatedFeedCost(Cattle $cattle, ?Carbon $asOf = null): float
    {
        $cattle->loadMissing('fatteningLotAssignments');
        $asOf ??= Carbon::today();
        $total = 0.0;

        foreach ($cattle->fatteningLotAssignments as $assignment) {
            $end = $assignment->exit_date ?? $assignment->removed_at ?? $asOf;
            if ($end->lt($assignment->entry_date)) {
                continue;
            }
            $total += $this->allocateFeedCost($assignment, $assignment->entry_date, $end);
        }

        return round($total, 2);
    }

    private function allocateFeedCost(FatteningLotAnimal $assignment, Carbon $from, Carbon $to): float
    {
        $lotFeed = (float) MaterialExpense::query()
            ->where('fattening_lot_id', $assignment->fattening_lot_id)
            ->whereBetween('expense_date', [$from->toDateString(), $to->toDateString()])
            ->sum('total_cost');

        if ($lotFeed <= 0) {
            return 0.0;
        }

        $animalsInLot = FatteningLotAnimal::query()
            ->where('fattening_lot_id', $assignment->fattening_lot_id)
            ->where('entry_date', '<=', $to->toDateString())
            ->where(function ($q) use ($from) {
                $q->whereNull('removed_at')
                    ->orWhere('removed_at', '>=', $from->toDateString());
            })
            ->count();

        return round($lotFeed / max(1, $animalsInLot), 2);
    }

    private function lifetimeWeightGain(Cattle $cattle, float $exitWeightKg): ?float
    {
        $first = WeightRecord::query()
            ->where('cattle_id', $cattle->id)
            ->orderBy('weighed_at')
            ->value('weight_kg');

        if ($first === null) {
            return null;
        }

        return round($exitWeightKg - (float) $first, 2);
    }
}
