<?php

namespace Kylin\Pet\Services;

use App\Models\Appointment;
use App\Models\Pet;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Kylin\Pet\Enums\AppointmentStatus;

/**
 * 预约服务 - 业务逻辑层
 * 处理预约创建、状态流转、冲突检测
 */
class AppointmentService
{
    /**
     * 创建预约（含冲突检测）
     */
    public function create(array $data): Appointment
    {
        return DB::transaction(function () use ($data) {
            // 检查同一宠物同一时段是否已有预约
            $conflict = Appointment::where('pet_id', $data['pet_id'])
                ->where('appointment_date', $data['appointment_date'])
                ->where('appointment_time', $data['appointment_time'])
                ->whereNotIn('status', [AppointmentStatus::CANCELLED->value])
                ->exists();

            if ($conflict) {
                throw new \InvalidArgumentException('该宠物在此时段已有预约');
            }

            $data['status'] = AppointmentStatus::PENDING->value;
            $appointment = Appointment::create($data);

            $this->audit('appointment_created', $appointment, [
                'pet_id' => $appointment->pet_id,
                'appointment_date' => $appointment->appointment_date,
            ]);

            return $appointment;
        });
    }

    /**
     * 确认预约
     */
    public function confirm(Appointment $appointment): Appointment
    {
        $this->validateTransition($appointment, AppointmentStatus::CONFIRMED);

        return DB::transaction(function () use ($appointment) {
            $appointment->update(['status' => AppointmentStatus::CONFIRMED]);

            $this->audit('appointment_confirmed', $appointment, [
                'pet_id' => $appointment->pet_id,
            ]);

            return $appointment->fresh();
        });
    }

    /**
     * 完成预约
     */
    public function complete(Appointment $appointment): Appointment
    {
        $this->validateTransition($appointment, AppointmentStatus::COMPLETED);

        return DB::transaction(function () use ($appointment) {
            $appointment->update(['status' => AppointmentStatus::COMPLETED]);

            $this->audit('appointment_completed', $appointment, [
                'pet_id' => $appointment->pet_id,
            ]);

            return $appointment->fresh();
        });
    }

    /**
     * 取消预约
     */
    public function cancel(Appointment $appointment): Appointment
    {
        $currentStatus = AppointmentStatus::from($appointment->status);

        if (!in_array($currentStatus, [AppointmentStatus::PENDING, AppointmentStatus::CONFIRMED])) {
            throw new \InvalidArgumentException('当前状态不可取消');
        }

        return DB::transaction(function () use ($appointment) {
            $appointment->update(['status' => AppointmentStatus::CANCELLED]);

            $this->audit('appointment_cancelled', $appointment, [
                'pet_id' => $appointment->pet_id,
            ]);

            return $appointment->fresh();
        });
    }

    /**
     * 获取某日预约日程
     */
    public function getDailySchedule(string $date, ?int $organizationId = null): array
    {
        $query = Appointment::with(['pet', 'user'])
            ->where('appointment_date', $date)
            ->orderBy('appointment_time');

        if ($organizationId) {
            $query->whereHas('pet', fn($q) => $q->where('organization_id', $organizationId));
        }

        return $query->get()->groupBy('appointment_time')->toArray();
    }

    /**
     * 验证状态流转合法性
     */
    private function validateTransition(Appointment $appointment, AppointmentStatus $targetStatus): void
    {
        $currentStatus = AppointmentStatus::from($appointment->status);

        if (!$currentStatus->canTransitionTo($targetStatus)) {
            throw new \InvalidArgumentException(
                "预约状态不可从 {$currentStatus->label()} 变更为 {$targetStatus->label()}"
            );
        }
    }

    /**
     * 记录预约审计日志
     *
     * 依据《动物防疫法》和《个人信息保护法》，
     * 宠物预约创建、确认、完成、取消等操作需记录审计日志。
     */
    private function audit(string $event, Appointment $appointment, array $extra = []): void
    {
        if (! class_exists(\Kylin\AuditLog\Models\AuditLog::class)) {
            return;
        }

        try {
            \Kylin\AuditLog\Models\AuditLog::create([
                'event' => $event,
                'model_type' => Appointment::class,
                'model_id' => $appointment->id,
                'new_values' => $extra,
                'old_values' => null,
                'user_id' => auth()->id(),
                'ip' => request()?->ip(),
                'url' => request()?->fullUrl(),
                'tag' => 'pet-appointment',
            ]);
        } catch (\Throwable $e) {
            logger()->warning('预约审计日志写入失败', [
                'error' => $e->getMessage(),
                'appointment_id' => $appointment->id,
                'event' => $event,
            ]);
        }
    }
}
