<?php

namespace App\Filament\Employee\Widgets;

use App\Models\Attendance;
use App\Models\Holiday;
use Carbon\Carbon;
use Filament\Forms\Components\Select;
use Filament\Widgets\Widget;
use Illuminate\Contracts\View\View;

class AttendanceCalendarWidget extends Widget
{
    protected static string $view = 'filament.employee.widgets.attendance-calendar-widget';

    protected int|string|array $columnSpan = 'full';

    protected static ?int $sort = 2;

    public int $selectedMonth;
    public int $selectedYear;
    public ?array $selectedDate = null;

    public function mount(): void
    {
        $this->selectedMonth = now()->month;
        $this->selectedYear = now()->year;
    }

    public function previousMonth(): void
    {
        $date = Carbon::create($this->selectedYear, $this->selectedMonth, 1)->subMonth();
        $this->selectedMonth = $date->month;
        $this->selectedYear = $date->year;
        $this->selectedDate = null;
    }

    public function nextMonth(): void
    {
        $date = Carbon::create($this->selectedYear, $this->selectedMonth, 1)->addMonth();
        $this->selectedMonth = $date->month;
        $this->selectedYear = $date->year;
        $this->selectedDate = null;
    }

    public function selectDate(string $date): void
    {
        $attendance = Attendance::where('user_id', auth()->id())
            ->whereDate('date', $date)
            ->with('office')
            ->first();

        $carbonDate = Carbon::parse($date);
        $isHoliday = Holiday::whereDate('date', $date)->first();
        $isWeekend = $carbonDate->isWeekend();

        // Prepare map data
        $mapMarkers = [];
        $mapOffices = [];

        if ($attendance) {
            // Add check-in marker
            if ($attendance->check_in_latitude && $attendance->check_in_longitude) {
                $mapMarkers[] = [
                    'lat' => (float) $attendance->check_in_latitude,
                    'lng' => (float) $attendance->check_in_longitude,
                    'type' => 'check_in',
                    'name' => auth()->user()->name,
                    'time' => $attendance->check_in_time ? Carbon::parse($attendance->check_in_time)->format('H:i') : null,
                    'address' => $attendance->check_in_address,
                    'distance' => $attendance->check_in_distance,
                ];
            }

            // Add check-out marker
            if ($attendance->check_out_latitude && $attendance->check_out_longitude) {
                $mapMarkers[] = [
                    'lat' => (float) $attendance->check_out_latitude,
                    'lng' => (float) $attendance->check_out_longitude,
                    'type' => 'check_out',
                    'name' => auth()->user()->name,
                    'time' => $attendance->check_out_time ? Carbon::parse($attendance->check_out_time)->format('H:i') : null,
                    'address' => $attendance->check_out_address,
                    'distance' => $attendance->check_out_distance,
                ];
            }

            // Add office marker
            if ($attendance->office && $attendance->office->latitude && $attendance->office->longitude) {
                $mapOffices[] = [
                    'lat' => (float) $attendance->office->latitude,
                    'lng' => (float) $attendance->office->longitude,
                    'name' => $attendance->office->name,
                    'address' => $attendance->office->address,
                    'radius' => $attendance->office->radius ?? 100,
                ];
            }
        }

        // Check if business trip has incomplete location
        $hasIncompleteLocation = $attendance
            && $attendance->type === 'business_trip'
            && (empty($attendance->check_in_latitude) || empty($attendance->check_in_longitude));

        $this->selectedDate = [
            'date' => $date,
            'formatted_date' => $carbonDate->translatedFormat('l, d F Y'),
            'attendance' => $attendance ? [
                'id' => $attendance->id,
                'status' => $attendance->status,
                'type' => $attendance->type,
                'check_in_time' => $attendance->check_in_time ? Carbon::parse($attendance->check_in_time)->format('H:i') : null,
                'check_out_time' => $attendance->check_out_time ? Carbon::parse($attendance->check_out_time)->format('H:i') : null,
                'work_duration' => $attendance->work_duration,
                'check_in_notes' => $attendance->check_in_notes,
                'check_out_notes' => $attendance->check_out_notes,
                'has_incomplete_location' => $hasIncompleteLocation,
            ] : null,
            'is_holiday' => $isHoliday ? true : false,
            'holiday_name' => $isHoliday?->name,
            'is_weekend' => $isWeekend,
            'is_today' => $carbonDate->isToday(),
            'is_future' => $carbonDate->isFuture(),
            'map_markers' => $mapMarkers,
            'map_offices' => $mapOffices,
            'has_location' => count($mapMarkers) > 0,
            'has_incomplete_location' => $hasIncompleteLocation,
        ];
    }

    public function closeDetail(): void
    {
        $this->selectedDate = null;
    }

    public function getCalendarData(): array
    {
        $user = auth()->user();
        $startOfMonth = Carbon::create($this->selectedYear, $this->selectedMonth, 1)->startOfMonth();
        $endOfMonth = $startOfMonth->copy()->endOfMonth();

        // Get all attendances for the month
        $attendances = Attendance::where('user_id', $user->id)
            ->whereBetween('date', [$startOfMonth, $endOfMonth])
            ->get()
            ->keyBy(fn($a) => Carbon::parse($a->date)->format('Y-m-d'));

        // Get holidays
        $holidays = Holiday::whereBetween('date', [$startOfMonth, $endOfMonth])
            ->get()
            ->keyBy(fn($h) => Carbon::parse($h->date)->format('Y-m-d'));

        // Build calendar grid
        $calendar = [];
        $currentDate = $startOfMonth->copy()->startOfWeek(Carbon::SUNDAY);
        $today = now()->toDateString();

        while ($currentDate <= $endOfMonth->copy()->endOfWeek(Carbon::SATURDAY)) {
            $week = [];
            for ($i = 0; $i < 7; $i++) {
                $dateStr = $currentDate->format('Y-m-d');
                $attendance = $attendances->get($dateStr);
                $holiday = $holidays->get($dateStr);
                $isCurrentMonth = $currentDate->month === $this->selectedMonth;
                $isWeekend = $currentDate->isWeekend();
                $isToday = $dateStr === $today;
                $isFuture = $currentDate->isFuture();

                $status = 'none';
                if (!$isCurrentMonth) {
                    $status = 'other_month';
                } elseif ($holiday) {
                    $status = 'holiday';
                } elseif ($isWeekend && !$attendance) {
                    $status = 'weekend';
                } elseif ($attendance) {
                    $status = $attendance->status;
                } elseif (!$isFuture) {
                    $status = 'absent';
                }

                // Check if business trip has incomplete location
                $hasIncompleteLocation = $attendance
                    && $attendance->type === 'business_trip'
                    && (empty($attendance->check_in_latitude) || empty($attendance->check_in_longitude));

                $week[] = [
                    'date' => $dateStr,
                    'day' => $currentDate->day,
                    'status' => $status,
                    'type' => $attendance?->type,
                    'is_current_month' => $isCurrentMonth,
                    'is_today' => $isToday,
                    'is_future' => $isFuture,
                    'is_weekend' => $isWeekend,
                    'holiday_name' => $holiday?->name,
                    'check_in' => $attendance?->check_in_time ? Carbon::parse($attendance->check_in_time)->format('H:i') : null,
                    'check_out' => $attendance?->check_out_time ? Carbon::parse($attendance->check_out_time)->format('H:i') : null,
                    'has_incomplete_location' => $hasIncompleteLocation,
                ];

                $currentDate->addDay();
            }
            $calendar[] = $week;
        }

        return $calendar;
    }

    public function getMonthLabel(): string
    {
        return Carbon::create($this->selectedYear, $this->selectedMonth, 1)->translatedFormat('F Y');
    }

    public function getStatistics(): array
    {
        $user = auth()->user();
        $startOfMonth = Carbon::create($this->selectedYear, $this->selectedMonth, 1)->startOfMonth();
        $endOfMonth = $startOfMonth->copy()->endOfMonth();

        $attendances = Attendance::where('user_id', $user->id)
            ->whereBetween('date', [$startOfMonth, $endOfMonth])
            ->get();

        return [
            'present' => $attendances->where('status', 'present')->count(),
            'late' => $attendances->where('status', 'late')->count(),
            'absent' => $this->countAbsentDays($startOfMonth, $endOfMonth, $attendances),
            'sick' => $attendances->where('status', 'sick')->count(),
            'leave' => $attendances->where('status', 'leave')->count(),
            'permission' => $attendances->where('status', 'permission')->count(),
            'business_trip' => $attendances->where('type', 'business_trip')->count(),
            'wfh' => $attendances->where('type', 'wfh')->count(),
        ];
    }

    private function countAbsentDays(Carbon $start, Carbon $end, $attendances): int
    {
        $count = 0;
        $current = $start->copy();
        $today = now()->startOfDay();

        $holidays = Holiday::whereBetween('date', [$start, $end])
            ->pluck('date')
            ->map(fn($d) => Carbon::parse($d)->format('Y-m-d'))
            ->toArray();

        $attendanceDates = $attendances->pluck('date')
            ->map(fn($d) => Carbon::parse($d)->format('Y-m-d'))
            ->toArray();

        while ($current <= $end && $current < $today) {
            $dateStr = $current->format('Y-m-d');
            $isWeekend = $current->isWeekend();
            $isHoliday = in_array($dateStr, $holidays);
            $hasAttendance = in_array($dateStr, $attendanceDates);

            if (!$isWeekend && !$isHoliday && !$hasAttendance) {
                $count++;
            }

            $current->addDay();
        }

        return $count;
    }

    public function canBackdate(): bool
    {
        $user = auth()->user();
        $company = $user->company;

        return $company?->backdate_enabled ?? false;
    }
}
