<?php

declare(strict_types=1);

final class LocationHistoryService
{
    private const TRACKED = ['status', 'refuge_room', 'care_box_key', 'current_address'];

    public static function snapshot(array $animal): array
    {
        $snapshot = [];
        foreach (self::TRACKED as $field) {
            $value = trim((string) ($animal[$field] ?? ''));
            $snapshot[$field] = $value === '' ? null : $value;
        }
        return $snapshot;
    }

    public static function record(
        PDO $db,
        int $animalId,
        ?array $before,
        array $after,
        string $source,
        ?string $reason = null,
        ?string $movedAt = null,
    ): bool {
        $from = self::snapshot($before ?? []);
        $to = self::snapshot($after);
        if ($before !== null && $from === $to) {
            return false;
        }

        $stmt = $db->prepare('INSERT INTO animal_location_history (
            animal_id,from_status,from_refuge_room,from_care_box_key,from_address,
            to_status,to_refuge_room,to_care_box_key,to_address,reason,source,moved_at,user_id
        ) VALUES (
            :animal,:from_status,:from_room,:from_box,:from_address,
            :to_status,:to_room,:to_box,:to_address,:reason,:source,:moved_at,:user
        )');
        $stmt->execute([
            ':animal' => $animalId,
            ':from_status' => $from['status'],
            ':from_room' => $from['refuge_room'],
            ':from_box' => $from['care_box_key'],
            ':from_address' => $from['current_address'],
            ':to_status' => $to['status'],
            ':to_room' => $to['refuge_room'],
            ':to_box' => $to['care_box_key'],
            ':to_address' => $to['current_address'],
            ':reason' => ($reason = trim((string) $reason)) !== '' ? $reason : null,
            ':source' => $source,
            ':moved_at' => $movedAt ?: date('Y-m-d H:i:s'),
            ':user' => Auth::id(),
        ]);
        return true;
    }

    public static function label(array $row, string $prefix): string
    {
        $status = trim((string) ($row[$prefix . '_status'] ?? ''));
        $room = trim((string) ($row[$prefix . '_refuge_room'] ?? ''));
        $box = trim((string) ($row[$prefix . '_care_box_key'] ?? ''));
        $address = trim((string) ($row[$prefix . '_address'] ?? ''));

        $label = match ($status) {
            'refuge' => $room !== '' ? 'Refuge · ' . self::roomName($room) : 'Refuge · Salle non attribuée',
            'soin' => $room !== '' ? self::roomName($room) : 'Infirmerie',
            'quarantaine' => $room !== '' ? self::roomName($room) : 'Salle de quarantaine',
            'fa' => 'Famille d’accueil',
            'fa_permanente' => 'FA permanente',
            'reserve', 'réservé' => 'Réservé',
            'adopte', 'adopté' => 'Adopté',
            'hospitalise', 'hospitalisé' => 'Hospitalisé',
            'isolation' => 'Isolation',
            'decede', 'décédé' => 'Décédé',
            'enfui', 'fugue' => 'Enfui',
            '' => 'Emplacement antérieur inconnu',
            default => ucfirst(str_replace('_', ' ', $status)),
        };
        if ($box !== '' && in_array($status, ['soin', 'quarantaine'], true)) {
            $label .= ' · Box ' . self::boxLabel($box);
        }
        if (
            $address !== '' &&
            in_array($status, ['fa', 'fa_permanente', 'adopte', 'adopté', 'hospitalise', 'hospitalisé'], true)
        ) {
            $label .= ' · ' . $address;
        }
        return $label;
    }

    private static function boxLabel(string $box): string
    {
        return match ($box) {
            'top_a' => 'haut gauche',
            'top_b' => 'haut centre',
            'top_c' => 'haut droite',
            'top_ab' => 'haut gauche double',
            'top_bc' => 'haut droite double',
            'top_all' => 'haut complet',
            'bottom_a' => 'bas gauche',
            'bottom_b' => 'bas droite',
            'bottom_all' => 'bas complet',
            default => str_replace('_', ' ', $box),
        };
    }

    private static function roomName(string $code): string
    {
        static $rooms = null;
        $rooms ??= ShelterRoomService::byCode(false);
        return (string) ($rooms[$code]['name'] ?? $code);
    }
}
