<?php

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;
use App\Models\Leave;
use App\Models\User;
use App\Notifications\SystemAlertNotification;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Schema;

class LeaveController extends Controller
{
    public function index(Request $request)
    {
        if (! Schema::hasTable('leaves')) {
            return response()->json([
                'leaves' => [],
                'has_approved_today' => false,
            ]);
        }

        $user = $request->user();
        $user->loadMissing('employee');

        $tz = 'Asia/Baghdad';
        $today = Carbon::now($tz)->toDateString();

        $hasApprovedToday = Leave::query()
            ->where('user_id', $user->id)
            ->where('status', 'approved')
            ->whereDate('leave_date', $today)
            ->exists();

        $startOfMonth = Carbon::now($tz)->startOfMonth()->toDateString();
        $endOfMonth = Carbon::now($tz)->endOfMonth()->toDateString();

        $usedPaidLeaves = Leave::query()
            ->where('user_id', $user->id)
            ->where('leave_type', 'full_day')
            ->where('is_paid', true)
            ->whereIn('status', ['pending', 'approved'])
            ->whereBetween('leave_date', [$startOfMonth, $endOfMonth])
            ->count();

        $leaves = Leave::query()
            ->where('user_id', $user->id)
            ->orderByDesc('leave_date')
            ->orderByDesc('id')
            ->get()
            ->map(fn (Leave $leave) => $this->serializeLeave($leave))
            ->values();

        return response()->json([
            'leaves' => $leaves,
            'has_approved_today' => $hasApprovedToday,
            'used_paid_leaves_this_month' => $usedPaidLeaves,
        ]);
    }

    public function store(Request $request)
    {
        if (! Schema::hasTable('leaves')) {
            return response()->json([
                'message' => 'الخادم غير جاهز للإجازات بعد. يرجى تشغيل ترحيلات قاعدة البيانات (php artisan migrate).',
            ], 409);
        }
        if (! Schema::hasColumn('leaves', 'leave_time_from') || ! Schema::hasColumn('leaves', 'leave_time_to')) {
            return response()->json([
                'message' => 'الخادم غير جاهز للإجازات بعد. يرجى تشغيل ترحيلات قاعدة البيانات (php artisan migrate).',
            ], 409);
        }

        $user = $request->user();
        $user->loadMissing('employee');

        if (! $user->employee) {
            return response()->json([
                'message' => 'لا يوجد موظف مرتبط بهذا المستخدم',
            ], 409);
        }

        $validated = $request->validate([
            'leave_type' => 'required|in:full_day,timed',
            'leave_date' => 'required|date',
            'leave_time' => 'nullable|date_format:H:i',
            'leave_time_from' => 'nullable|date_format:H:i',
            'leave_time_to' => 'nullable|date_format:H:i',
            'reason' => 'nullable|string|max:2000',
            'is_paid' => 'nullable|boolean',
        ]);

        $tz = 'Asia/Baghdad';
        $nowLocal = Carbon::now($tz);

        $leaveDate = Carbon::parse($validated['leave_date'], $tz)->toDateString();

        if ($validated['leave_type'] === 'full_day') {
            $tomorrow = $nowLocal->copy()->addDay()->toDateString();
            if ($leaveDate !== $tomorrow) {
                return response()->json([
                    'message' => 'لا يمكن طلب إجازة يوم كامل إلا لليوم التالي فقط',
                ], 422);
            }

            $isProgrammer = (bool) ($user->employee->is_programmer ?? false);
            if (! $isProgrammer) {
                $attendanceTime = (string) ($user->employee->attendance_time ?? '');
                $departureTime = (string) ($user->employee->departure_time ?? '');
                if (! $this->isWithinWorkHours($nowLocal, $attendanceTime, $departureTime, $tz)) {
                    return response()->json([
                        'message' => 'يمكن طلب إجازة يوم كامل خلال وقت الدوام فقط',
                    ], 422);
                }
            }
        }

        $leaveTimeFrom = null;
        $leaveTimeTo = null;
        if ($validated['leave_type'] === 'timed') {
            $rawFrom = trim((string) ($validated['leave_time_from'] ?? ''));
            $rawTo = trim((string) ($validated['leave_time_to'] ?? ''));

            if ($rawFrom === '' || $rawTo === '') {
                return response()->json([
                    'message' => 'يرجى تحديد وقت الإجازة الزمنية من وإلى',
                ], 422);
            }

            $fromMinutes = $this->timeToMinutes($rawFrom);
            $toMinutes = $this->timeToMinutes($rawTo);
            if ($fromMinutes === null || $toMinutes === null || $toMinutes <= $fromMinutes) {
                return response()->json([
                    'message' => 'وقت الإجازة الزمنية غير صالح (يجب أن يكون "إلى" بعد "من")',
                ], 422);
            }

            $leaveTimeFrom = $this->normalizeTimeHm($rawFrom);
            $leaveTimeTo = $this->normalizeTimeHm($rawTo);
        }

        $isPaid = $validated['leave_type'] === 'timed'
            ? true
            : ($validated['is_paid'] ?? false);

        if ($validated['leave_type'] === 'full_day' && $isPaid) {
            $tz = 'Asia/Baghdad';
            $startOfMonth = Carbon::now($tz)->startOfMonth()->toDateString();
            $endOfMonth = Carbon::now($tz)->endOfMonth()->toDateString();

            $usedPaidLeaves = Leave::query()
                ->where('user_id', $user->id)
                ->where('leave_type', 'full_day')
                ->where('is_paid', true)
                ->whereIn('status', ['pending', 'approved'])
                ->whereBetween('leave_date', [$startOfMonth, $endOfMonth])
                ->count();

            if ($usedPaidLeaves >= 3) {
                return response()->json([
                    'message' => 'لقد استنفذت رصيد الإجازات المدفوعة لهذا الشهر (3 أيام)',
                ], 422);
            }
        }

        $leaveTime = isset($validated['leave_time']) && trim((string) $validated['leave_time']) !== ''
            ? trim((string) $validated['leave_time']).':00'
            : null;

        $leave = Leave::create([
            'user_id' => $user->id,
            'employee_id' => $user->employee->id,
            'leave_type' => $validated['leave_type'],
            'is_paid' => $isPaid,
            'leave_date' => $leaveDate,
            'leave_time' => $leaveTime,
            'leave_time_from' => $leaveTimeFrom,
            'leave_time_to' => $leaveTimeTo,
            'reason' => $validated['reason'] ?? null,
            'status' => 'pending',
        ]);

        $this->notifyAdminsForLeaveRequest($user, $leave);

        return response()->json([
            'message' => 'تم إرسال طلب الإجازة',
            'leave' => $this->serializeLeave($leave),
        ], 201);
    }

    private function serializeLeave(Leave $leave): array
    {
        return [
            'id' => $leave->id,
            'leave_type' => $leave->leave_type,
            'is_paid' => (bool) $leave->is_paid,
            'leave_date' => $leave->leave_date?->toDateString(),
            'leave_time' => $leave->leave_time,
            'leave_time_from' => $leave->leave_time_from,
            'leave_time_to' => $leave->leave_time_to,
            'reason' => $leave->reason,
            'status' => $leave->status,
            'created_at' => $leave->created_at?->toIso8601String(),
        ];
    }

    private function notifyAdminsForLeaveRequest($user, Leave $leave): void
    {
        if (! Schema::hasTable('notifications')) {
            return;
        }

        $employeeName = $user?->employee?->full_name ?? $user?->name ?? '—';

        $typeLabel = $leave->leave_type === 'timed' ? 'إجازة زمنية' : 'إجازة يوم كامل';
        $date = $leave->leave_date?->toDateString() ?? '';

        $timePart = '';
        if ($leave->leave_type === 'timed') {
            $from = is_string($leave->leave_time_from) ? trim($leave->leave_time_from) : '';
            $to = is_string($leave->leave_time_to) ? trim($leave->leave_time_to) : '';
            if ($from !== '' && $to !== '') {
                $timePart = ' - '.substr($from, 0, 5).' إلى '.substr($to, 0, 5);
            }
        }

        $paidLabel = $leave->leave_type === 'timed' ? 'مدفوعة' : ((bool) $leave->is_paid ? 'مدفوعة' : 'غير مدفوعة');

        $title = 'طلب إجازة';
        $body = trim($employeeName).' - '.$typeLabel.' - '.$paidLabel.' - '.$date.$timePart;

        $admins = User::query()
            ->where('is_admin', true)
            ->orWhereRaw('LOWER(username) = ?', ['admin'])
            ->orWhereHas('roles', fn ($q) => $q->whereIn('key', ['super_admin', 'admin']))
            ->get();

        foreach ($admins as $admin) {
            $admin->notify(new SystemAlertNotification($title, $body, [
                'event' => 'leave_requested',
                'leave_id' => $leave->id,
                'employee_id' => $leave->employee_id,
                'user_id' => $leave->user_id,
            ]));
        }
    }

    private function normalizeTimeHm(?string $time): ?string
    {
        $time = $time !== null ? trim($time) : null;
        if ($time === null || $time === '') {
            return null;
        }

        if (preg_match('/^\d{2}:\d{2}$/', $time)) {
            return $time.':00';
        }

        if (preg_match('/^\d{2}:\d{2}:\d{2}$/', $time)) {
            return $time;
        }

        return null;
    }

    private function timeToMinutes(string $time): ?int
    {
        $time = trim($time);
        if ($time === '') {
            return null;
        }

        if (preg_match('/^\d{2}:\d{2}$/', $time)) {
            $time = $time.':00';
        }

        if (! preg_match('/^\d{2}:\d{2}:\d{2}$/', $time)) {
            return null;
        }

        [$h, $m] = array_map('intval', explode(':', substr($time, 0, 5)));
        if ($h < 0 || $h > 23 || $m < 0 || $m > 59) {
            return null;
        }

        return $h * 60 + $m;
    }

    private function isWithinWorkHours(Carbon $nowLocal, string $attendanceTime, string $departureTime, string $tz): bool
    {
        $attendance = $this->normalizeTimeHm($attendanceTime);
        $departure = $this->normalizeTimeHm($departureTime);

        if (! $attendance || ! $departure) {
            return false;
        }

        $todayStart = Carbon::createFromFormat('Y-m-d H:i:s', $nowLocal->toDateString().' '.$attendance, $tz);
        $todayEnd = Carbon::createFromFormat('Y-m-d H:i:s', $nowLocal->toDateString().' '.$departure, $tz);
        if ($todayEnd->lessThanOrEqualTo($todayStart)) {
            $todayEnd->addDay();
        }

        if ($nowLocal->betweenIncluded($todayStart, $todayEnd)) {
            return true;
        }

        $yesterdayStart = $todayStart->copy()->subDay();
        $yesterdayEnd = $todayEnd->copy()->subDay();

        return $nowLocal->betweenIncluded($yesterdayStart, $yesterdayEnd);
    }
}
