<?php

namespace App\Services;

use App\Models\Cattle;
use App\Models\CattleHealthEvent;
use Carbon\Carbon;

class RanchHealthReportService
{
    /**
     * @return array{
     *   from: string|null,
     *   to: string|null,
     *   total_events: int,
     *   illness_count: int,
     *   by_type: array<string, int>,
     *   at_risk_mothers: list<array<string, mixed>>
     * }
     */
    public function summary(?Carbon $from = null, ?Carbon $to = null): array
    {
        $query = CattleHealthEvent::query()->with('cattle:id,ear_tag,gender,mother_id');

        if ($from && $to) {
            $query->whereBetween('event_date', [$from->toDateString(), $to->toDateString()]);
        }

        $events = $query->orderByDesc('event_date')->get();

        $byType = [];
        $totalCost = 0.0;
        $vaccinationCost = 0.0;
        foreach ($events as $event) {
            $byType[$event->event_type] = ($byType[$event->event_type] ?? 0) + 1;
            $cost = (float) ($event->materialExpense?->total_cost ?? $event->cost ?? 0);
            $totalCost += $cost;
            if (in_array($event->event_type, [
                CattleHealthEvent::TYPE_VACCINATION,
                CattleHealthEvent::TYPE_DEWORMING,
                CattleHealthEvent::TYPE_TREATMENT,
            ], true)) {
                $vaccinationCost += $cost;
            }
        }

        return [
            'from' => $from?->toDateString(),
            'to' => $to?->toDateString(),
            'total_events' => $events->count(),
            'total_cost' => round($totalCost, 2),
            'vaccination_cost' => round($vaccinationCost, 2),
            'illness_count' => $events->where('event_type', CattleHealthEvent::TYPE_ILLNESS)->count(),
            'by_type' => $byType,
            'by_type_labeled' => $this->labelTypes($byType),
            'at_risk_mothers' => $this->mothersWithSickOffspring(),
            'recent_illnesses' => $events
                ->where('event_type', CattleHealthEvent::TYPE_ILLNESS)
                ->take(20)
                ->map(fn (CattleHealthEvent $e) => [
                    'id' => $e->id,
                    'event_date' => $e->event_date->toDateString(),
                    'ear_tag' => $e->cattle?->ear_tag,
                    'cattle_id' => $e->cattle_id,
                    'title' => $e->title,
                    'outcome' => $e->outcome,
                ])
                ->values()
                ->all(),
        ];
    }

    /**
     * @return list<array<string, mixed>>
     */
    public function mothersWithSickOffspring(): array
    {
        $threshold = (int) config('ranch.health_alerts.offspring_illness_threshold', 2);

        $illnessCounts = CattleHealthEvent::query()
            ->where('event_type', CattleHealthEvent::TYPE_ILLNESS)
            ->whereHas('cattle', fn ($q) => $q->whereNotNull('mother_id'))
            ->get()
            ->groupBy(fn (CattleHealthEvent $e) => $e->cattle->mother_id)
            ->map(fn ($group) => $group->count());

        $rows = [];
        foreach ($illnessCounts as $motherId => $count) {
            if ($count < $threshold) {
                continue;
            }

            $mother = Cattle::find($motherId);
            if (! $mother) {
                continue;
            }

            $rows[] = [
                'mother_id' => $mother->id,
                'ear_tag' => $mother->ear_tag,
                'offspring_illness_events' => $count,
                'alert' => true,
            ];
        }

        usort($rows, fn ($a, $b) => $b['offspring_illness_events'] <=> $a['offspring_illness_events']);

        return $rows;
    }

    /**
     * @param  array<string, int>  $byType
     * @return list<array{key: string, label: string, count: int}>
     */
    private function labelTypes(array $byType): array
    {
        $labels = config('ranch.health_event_types', []);
        $result = [];
        foreach ($byType as $key => $count) {
            $result[] = [
                'key' => $key,
                'label' => $labels[$key] ?? $key,
                'count' => $count,
            ];
        }

        return $result;
    }
}
