<?php

namespace App\Services;

use App\Models\Cattle;
use App\Models\CattleCalvingEvent;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use InvalidArgumentException;

class CattleCalvingService
{
    public function __construct(
        private readonly WeightRecordService $weightRecordService,
        private readonly CattleLocationMovementService $locationMovementService,
        private readonly PastureService $pastureService,
    ) {}

    /**
     * @param  array<string, mixed>  $data
     * @return array{calf: Cattle, calving_event: CattleCalvingEvent}
     */
    public function register(array $data, ?int $userId = null): array
    {
        $mother = $this->resolveMother($data);
        $this->assertMotherEligible($mother);

        $calvingDate = Carbon::parse($data['calving_date']);
        if ($calvingDate->isFuture()) {
            throw new InvalidArgumentException('La fecha de parto no puede ser futura.');
        }

        return DB::transaction(function () use ($data, $mother, $calvingDate, $userId) {
            $earTag = isset($data['ear_tag']) ? trim((string) $data['ear_tag']) : '';
            $calf = Cattle::create([
                'ear_tag' => $earTag !== '' ? $earTag : null,
                'ear_tag_type' => $data['ear_tag_type'] ?? $mother->ear_tag_type ?? 'internal',
                'breed' => $data['breed'] ?? $mother->breed,
                'gender' => $data['gender'],
                'birth_date' => $calvingDate->toDateString(),
                'mother_id' => $mother->id,
                'status' => Cattle::STATUS_ACTIVE,
                'notes' => $data['notes'] ?? null,
            ]);

            $pastureId = $data['pasture_id'] ?? $mother->pasture_id;
            $pastureLocation = $data['pasture_location'] ?? $mother->pasture_location;
            $this->pastureService->applyToCattle($calf, $pastureId, $pastureLocation);
            $calf->save();
            $pasture = $calf->pasture_location;

            $birthWeight = isset($data['birth_weight_kg']) ? (float) $data['birth_weight_kg'] : null;

            $event = CattleCalvingEvent::create([
                'mother_id' => $mother->id,
                'calf_id' => $calf->id,
                'calving_date' => $calvingDate,
                'birth_weight_kg' => $birthWeight,
                'pasture_location' => $pasture,
                'notes' => $data['calving_notes'] ?? $data['notes'] ?? null,
                'user_id' => $userId,
            ]);

            if ($birthWeight !== null && $birthWeight > 0) {
                $this->weightRecordService->record(
                    $calf,
                    $birthWeight,
                    $calvingDate,
                    'Peso al nacer (parto)',
                    $userId,
                );
            }

            $this->locationMovementService->recordInitialPasture($calf, $calvingDate, $userId);

            return [
                'calf' => $calf->load('mother:id,ear_tag'),
                'calving_event' => $event->load(['mother:id,ear_tag', 'calf:id,ear_tag']),
            ];
        });
    }

    /**
     * @param  array<string, mixed>  $data
     */
    private function resolveMother(array $data): Cattle
    {
        if (! empty($data['mother_id'])) {
            return Cattle::findOrFail((int) $data['mother_id']);
        }

        $earTag = trim((string) ($data['mother_ear_tag'] ?? ''));
        if ($earTag === '') {
            throw new InvalidArgumentException('Indique la madre por arete o ID.');
        }

        $mother = Cattle::where('ear_tag', $earTag)->first();
        if (! $mother) {
            throw new InvalidArgumentException('No se encontró la vaca madre con ese arete.');
        }

        return $mother;
    }

    private function assertMotherEligible(Cattle $mother): void
    {
        if ($mother->gender !== 'female') {
            throw new InvalidArgumentException('La madre debe ser hembra.');
        }

        if (! $mother->isActive()) {
            throw new InvalidArgumentException('La madre debe estar activa en el inventario.');
        }
    }
}
