import { Head, router } from '@inertiajs/react';
import { addMonths, format, subMonths } from 'date-fns';
import { id } from 'date-fns/locale';
import {
    ChevronLeft,
    ChevronRight,
    Clock,
    LogIn,
    LogOut,
} from 'lucide-react';
import { useMemo, useState, useCallback } from 'react';
import { toast } from 'sonner';
import { TodayAttendanceAlert } from '@/components/card/today-attendance-alert';
import { CameraCapture, LocationMap } from '@/components/inputs';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Card } from '@/components/ui/card';
import {
    Dialog,
    DialogContent,
    DialogHeader,
    DialogTitle,
} from '@/components/ui/dialog';
import {
    byMonth as attendanceByMonth,
    store,
    update,
} from '@/routes/admin/hr/attendances';

type Attendance = {
    id: number;
    employee_id: number;
    attendance_date: string;
    check_in_at: string | null;
    check_out_at: string | null;
    check_in_photo: string | null;
    check_out_photo: string | null;
    check_in_latitude: number;
    check_in_longitude: number;
    check_out_latitude: number | null;
    check_out_longitude: number | null;
    work_duration_minutes: number | null;
    employee_name: string;
};

type Leave = {
    id: number;
    employee_id: number;
    start_date: string;
    end_date: string;
    total_days: number;
    status: string;
    employee_name: string;
};

type Employee = {
    id: number;
    name: string;
};

type Props = {
    attendances: Attendance[];
    leaves: Leave[];
    employees?: Employee[];
    todayAttendance: Attendance | null;
    currentYear: number;
    currentMonth: number;
    hrSettings: {
        scheduled_check_in_time: string;
        scheduled_check_out_time: string;
    };
    isOnLeave: boolean;
    canCheckIn: boolean;
    isAdmin: boolean;
    highlight?: number;
};

const WEEKDAYS = ['Min', 'Sen', 'Sel', 'Rab', 'Kam', 'Jum', 'Sab'];

function getDaysInMonth(year: number, month: number): number {
    return new Date(year, month, 0).getDate();
}

function getFirstDayOfMonth(year: number, month: number): number {
    return new Date(year, month - 1, 1).getDay();
}

function isSameDay(d1: Date, d2: Date): boolean {
    return (
        d1.getDate() === d2.getDate() &&
        d1.getMonth() === d2.getMonth() &&
        d1.getFullYear() === d2.getFullYear()
    );
}

function isWeekend(date: Date): boolean {
    const day = date.getDay();

    return day === 0 || day === 6;
}

function isLate(
    checkInAt: string | null,
    officeHour: number,
    officeMinute: number,
): boolean {
    if (!checkInAt) {
        return false;
    }

    const d = new Date(checkInAt);
    const h = d.getHours();
    const m = d.getMinutes();

    return h > officeHour || (h === officeHour && m > officeMinute);
}

function getLateMinutes(
    checkInAt: string | null,
    officeHour: number,
    officeMinute: number,
): number {
    if (!checkInAt || !isLate(checkInAt, officeHour, officeMinute)) {
        return 0;
    }

    const d = new Date(checkInAt);
    const officeStart = new Date(d);
    officeStart.setHours(officeHour, officeMinute, 0, 0);

    return Math.ceil((d.getTime() - officeStart.getTime()) / 60000);
}

function formatMinutes(minutes: number | null): string {
    if (!minutes) {
        return '-';
    }

    const hours = Math.floor(minutes / 60);
    const mins = Math.floor(minutes % 60);

    if (mins === 0) {
        return `${hours} jam`;
    }

    return `${hours} jam ${mins} menit`;
}

export default function AttendanceIndex({
    attendances: initialAttendances,
    leaves: initialLeaves,
    employees: initialEmployees = [],
    todayAttendance,
    currentYear,
    currentMonth,
    hrSettings,
    isOnLeave,
    canCheckIn,
    isAdmin,
    highlight,
}: Props) {
    const [officeHour, officeMinute] = hrSettings.scheduled_check_in_time
        .split(':')
        .map(Number);
    const [viewDate, setViewDate] = useState(
        new Date(currentYear, currentMonth - 1),
    );
    const [selectedDate, setSelectedDate] = useState<Date>(new Date());
    const [showCamera, setShowCamera] = useState(false);
    const [actionType, setActionType] = useState<'check-in' | 'check-out'>(
        'check-in',
    );
    const [locationLoading, setLocationLoading] = useState(false);
    const [detailAttendance, setDetailAttendance] = useState<Attendance | null>(
        null,
    );
    const [attendances, setAttendances] = useState<Attendance[]>(initialAttendances);
    const [leaves, setLeaves] = useState<Leave[]>(initialLeaves);
    const [employees, setEmployees] = useState<Employee[]>(initialEmployees);
    const [loadingMonth, setLoadingMonth] = useState(false);

    const viewYear = viewDate.getFullYear();
    const viewMonth = viewDate.getMonth() + 1;

    const fetchMonthData = useCallback(async (year: number, month: number) => {
        setLoadingMonth(true);

        try {
            const url = attendanceByMonth.url({ query: { year, month } });
            const res = await fetch(url);

            if (res.ok) {
                const data = await res.json();
                setAttendances(data.attendances);
                setLeaves(data.leaves);
                setEmployees(data.employees);
            }
        } finally {
            setLoadingMonth(false);
        }
    }, []);

    const attendanceByDate = useMemo(() => {
        const map = new Map<string, Attendance[]>();
        attendances.forEach((att) => {
            const existing = map.get(att.attendance_date) ?? [];
            existing.push(att);
            map.set(att.attendance_date, existing);
        });

        return map;
    }, [attendances]);

    const leavesByDate = useMemo(() => {
        const map = new Map<string, Leave[]>();
        leaves.forEach((leave) => {
            const start = new Date(leave.start_date);
            const end = new Date(leave.end_date);
            const current = new Date(start);

            while (current <= end) {
                const dateStr = format(current, 'yyyy-MM-dd');
                const existing = map.get(dateStr) ?? [];
                existing.push(leave);
                map.set(dateStr, existing);
                current.setDate(current.getDate() + 1);
            }
        });

        return map;
    }, [leaves]);

    const calendarDays = useMemo(() => {
        const daysInMonth = getDaysInMonth(viewYear, viewMonth);
        const firstDay = getFirstDayOfMonth(viewYear, viewMonth);
        const prevMonthDays = getDaysInMonth(
            viewYear,
            viewMonth === 1 ? 12 : viewMonth - 1,
        );

        const days: { day: number; isCurrentMonth: boolean; date: Date }[] = [];

        for (let i = firstDay - 1; i >= 0; i--) {
            const d = prevMonthDays - i;
            const m = viewMonth === 1 ? 12 : viewMonth - 1;
            const y = viewMonth === 1 ? viewYear - 1 : viewYear;
            days.push({
                day: d,
                isCurrentMonth: false,
                date: new Date(y, m - 1, d),
            });
        }

        for (let i = 1; i <= daysInMonth; i++) {
            days.push({
                day: i,
                isCurrentMonth: true,
                date: new Date(viewYear, viewMonth - 1, i),
            });
        }

        const remaining = 42 - days.length;

        for (let i = 1; i <= remaining; i++) {
            const m = viewMonth === 12 ? 1 : viewMonth + 1;
            const y = viewMonth === 12 ? viewYear + 1 : viewYear;
            days.push({
                day: i,
                isCurrentMonth: false,
                date: new Date(y, m - 1, i),
            });
        }

        return days;
    }, [viewYear, viewMonth]);

    const handlePrevMonth = () => {
        const newDate = subMonths(viewDate, 1);
        setViewDate(newDate);
        fetchMonthData(newDate.getFullYear(), newDate.getMonth() + 1);
    };

    const handleNextMonth = () => {
        const newDate = addMonths(viewDate, 1);
        setViewDate(newDate);
        fetchMonthData(newDate.getFullYear(), newDate.getMonth() + 1);
    };

    const handleGoToToday = () => {
        const now = new Date();
        setViewDate(now);
        setSelectedDate(now);
        fetchMonthData(now.getFullYear(), now.getMonth() + 1);
    };

    const handleCameraCapture = (dataUrl: string) => {
        setShowCamera(false);
        setLocationLoading(true);

        if (!navigator.geolocation) {
            setLocationLoading(false);
            toast.error('Geolocation tidak didukung di browser ini.');

            return;
        }

        navigator.geolocation.getCurrentPosition(
            (position) => {
                setLocationLoading(false);
                const formData = new FormData();
                formData.append('photo', dataUrl);
                formData.append(
                    'latitude',
                    position.coords.latitude.toString(),
                );
                formData.append(
                    'longitude',
                    position.coords.longitude.toString(),
                );

                if (actionType === 'check-in') {
                    router.post(store(), formData, { preserveScroll: true });
                } else if (actionType === 'check-out' && todayAttendance) {
                    router.put(update(todayAttendance.id), formData, {
                        preserveScroll: true,
                    });
                }
            },
            () => {
                setLocationLoading(false);
                toast.error(
                    'Gagal mendapatkan lokasi. Pastikan izin lokasi diberikan.',
                );
            },
            { enableHighAccuracy: true, timeout: 10000 },
        );
    };

    const handleCheckIn = () => {
        setActionType('check-in');
        setShowCamera(true);
    };

    const handleCheckOut = () => {
        setActionType('check-out');
        setShowCamera(true);
    };

    function formatTime(dateStr: string | null): string {
        if (!dateStr) {
            return '-';
        }

        return format(new Date(dateStr), 'HH:mm');
    }

    const today = new Date();

    return (
        <>
            <Head title="Presensi" />

            <div className="flex h-full flex-1 flex-col gap-6 overflow-x-auto p-4 md:p-6">
                <div>
                    <h2 className="text-2xl font-semibold tracking-tight">
                        Presensi
                    </h2>
                    {highlight && (
                        <p className="mt-1 text-sm text-muted-foreground">
                            Menampilkan presensi dari notifikasi.
                            <button
                                onClick={() => {
                                    const now = new Date();
                                    setViewDate(now);
                                    setSelectedDate(now);
                                    fetchMonthData(currentYear, currentMonth);
                                }}
                                className="ml-1 text-primary underline underline-offset-4 hover:text-primary/80"
                            >
                                Tampilkan semua
                            </button>
                        </p>
                    )}
                </div>

                {!isAdmin && (
                    <TodayAttendanceAlert
                        todayAttendance={todayAttendance}
                        isOnLeave={isOnLeave}
                        canCheckIn={canCheckIn}
                        locationLoading={locationLoading}
                        onCheckIn={handleCheckIn}
                        onCheckOut={handleCheckOut}
                    />
                )}


                <Card className="py-0!">
                    <div className="flex items-center justify-between border-b px-6 py-4">
                        <div className="flex items-center gap-3">
                            <div className="flex flex-col items-center overflow-hidden rounded-lg ring-1 ring-border">
                                <div className="bg-muted px-3 py-0.5">
                                    <span className="text-xs font-semibold text-muted-foreground uppercase">
                                        {format(today, 'MMM', {
                                            locale: id,
                                        })}
                                    </span>
                                </div>
                                <div className="px-3 py-1">
                                    <span className="text-lg font-bold text-primary">
                                        {format(today, 'dd')}
                                    </span>
                                </div>
                            </div>
                            <div>
                                <h3 className="text-lg font-semibold text-foreground">
                                    {format(viewDate, 'MMMM yyyy', {
                                        locale: id,
                                    })}
                                </h3>
                            </div>
                        </div>
                        <div className="flex items-center gap-1">
                            <Button
                                variant="ghost"
                                size="icon"
                                className="h-8 w-8"
                                onClick={handlePrevMonth}
                            >
                                <ChevronLeft className="h-4 w-4" />
                            </Button>
                            <Button
                                variant="ghost"
                                size="sm"
                                className="h-8 px-3 text-xs font-medium"
                                onClick={handleGoToToday}
                            >
                                Hari ini
                            </Button>
                            <Button
                                variant="ghost"
                                size="icon"
                                className="h-8 w-8"
                                onClick={handleNextMonth}
                            >
                                <ChevronRight className="h-4 w-4" />
                            </Button>
                        </div>
                    </div>

                    {isAdmin && (
                        <div className="flex items-center gap-3 border-b px-6 py-2 text-xs text-muted-foreground">
                            <Badge variant="default" className="text-[10px]">Hadir</Badge>
                            <Badge variant="destructive" className="text-[10px]">Terlambat</Badge>
                            <Badge className="text-[10px] bg-purple-100 text-purple-700 hover:bg-purple-100">Cuti</Badge>
                        </div>
                    )}

                    <div className="overflow-x-auto">
                        <div className="grid min-w-[700px] grid-cols-7 border-b">
                            {WEEKDAYS.map((day) => (
                                <div
                                    key={day}
                                    className="flex items-center justify-center py-3 text-xs font-medium text-muted-foreground"
                                >
                                    {day}
                                </div>
                            ))}
                        </div>

                        <div className="grid min-w-[700px] grid-cols-7">
                            {calendarDays.map((cell, idx) => {
                                const dateStr = format(cell.date, 'yyyy-MM-dd');
                                const dayAttendances = attendanceByDate.get(dateStr) ?? [];
                                const dayLeaves = leavesByDate.get(dateStr) ?? [];
                                const isSelected = isSameDay(
                                    cell.date,
                                    selectedDate,
                                );
                                const isTodayDate = isSameDay(
                                    cell.date,
                                    new Date(),
                                );

                                const todayMidnight = new Date();
                                todayMidnight.setHours(0, 0, 0, 0);
                                const cellDate = new Date(cell.date);
                                cellDate.setHours(0, 0, 0, 0);

                                const isPastDate = cellDate < todayMidnight;
                                const isFutureDate = cellDate > todayMidnight;
                                const showAbsent =
                                    cell.isCurrentMonth &&
                                    isPastDate &&
                                    !isWeekend(cell.date) &&
                                    dayAttendances.length === 0 &&
                                    dayLeaves.length === 0;

                                return (
                                    <div
                                        key={idx}
                                        onClick={() => {
                                            setSelectedDate(cell.date);

                                            if (!isAdmin && dayAttendances.length > 0) {
                                                setDetailAttendance(dayAttendances[0]);
                                            }
                                        }}
                                        className={`group relative flex min-h-[100px] flex-col p-2 text-left transition-colors hover:bg-muted/50 ${!cell.isCurrentMonth
                                            ? 'bg-muted/30 text-muted-foreground/50'
                                            : ''
                                            } ${isSelected ? 'bg-muted/50' : ''} ${!isAdmin && dayAttendances.length > 0 ? 'cursor-pointer' : ''
                                            }`}
                                        style={{
                                            borderRight: '1px solid var(--border)',
                                            borderBottom: '1px solid var(--border)',
                                        }}
                                    >
                                        <div className="flex items-start justify-between">
                                            <span
                                                className={`flex h-7 w-7 items-center justify-center rounded-full text-xs font-semibold transition-colors ${isSelected
                                                    ? 'bg-primary text-primary-foreground'
                                                    : isTodayDate
                                                        ? 'bg-muted text-foreground'
                                                        : 'text-foreground'
                                                    }`}
                                            >
                                                {cell.day}
                                            </span>
                                        </div>
                                        <div className="mt-1 flex flex-col gap-0.5 overflow-hidden">
                                            {isAdmin ? (
                                                <>
                                                    {cell.isCurrentMonth && !isFutureDate && [...employees].sort((a, b) => a.name.localeCompare(b.name)).map((emp) => {
                                                        const att = dayAttendances.find((a) => a.employee_id === emp.id);
                                                        const leave = dayLeaves.find((l) => l.employee_id === emp.id);

                                                        if (att) {
                                                            const late = isLate(
                                                                att.check_in_at,
                                                                officeHour,
                                                                officeMinute,
                                                            );
                                                            const notCheckedOut = !att.check_out_at;

                                                            return (
                                                                <Badge
                                                                    key={emp.id}
                                                                    variant={notCheckedOut ? 'outline' : (late ? 'destructive' : 'default')}
                                                                    className={`w-full justify-center cursor-pointer truncate ${notCheckedOut ? 'border-orange-300 bg-orange-50 text-orange-700 hover:bg-orange-50' : ''}`}
                                                                    onClick={(e) => {
                                                                        e.stopPropagation();
                                                                        setDetailAttendance(att);
                                                                    }}
                                                                >
                                                                    {emp.name}
                                                                </Badge>
                                                            );
                                                        }

                                                        if (leave) {
                                                            return (
                                                                <Badge
                                                                    key={emp.id}
                                                                    className="w-full justify-center cursor-pointer truncate bg-purple-100 text-purple-700 hover:bg-purple-100"
                                                                >
                                                                    {emp.name}
                                                                </Badge>
                                                            );
                                                        }

                                                        if (cell.isCurrentMonth && !isFutureDate) {
                                                            return (
                                                                <Badge
                                                                    key={emp.id}
                                                                    variant="outline"
                                                                    className="w-full justify-center truncate text-muted-foreground"
                                                                >
                                                                    {emp.name}
                                                                </Badge>
                                                            );
                                                        }

                                                        return null;
                                                    })}
                                                </>
                                            ) : (
                                                <>
                                                    {dayAttendances.length > 0 && (() => {
                                                        const att = dayAttendances[0];
                                                        const late = isLate(
                                                            att.check_in_at,
                                                            officeHour,
                                                            officeMinute,
                                                        );
                                                        const lateMins = getLateMinutes(
                                                            att.check_in_at,
                                                            officeHour,
                                                            officeMinute,
                                                        );

                                                        return (
                                                            <>
                                                                <span
                                                                    className={`inline-flex items-center justify-center rounded-full px-1.5 py-0.5 text-[10px] font-semibold ${late ? 'bg-yellow-100 text-yellow-700' : 'bg-green-100 text-green-700'}`}
                                                                >
                                                                    {late
                                                                        ? 'Terlambat'
                                                                        : 'Hadir'}
                                                                </span>
                                                                <span className="text-[10px] text-muted-foreground">
                                                                    Masuk :{' '}
                                                                    {formatTime(
                                                                        att.check_in_at,
                                                                    )}
                                                                </span>
                                                                <span className="text-[10px] text-muted-foreground">
                                                                    Pulang :{' '}
                                                                    {formatTime(
                                                                        att.check_out_at,
                                                                    )}
                                                                </span>
                                                                {late && (
                                                                    <span className="text-[10px] text-yellow-600">
                                                                        Telat :{' '}
                                                                        {formatMinutes(
                                                                            lateMins,
                                                                        )}{' '}
                                                                        menit
                                                                    </span>
                                                                )}
                                                                <span className="text-[10px] text-muted-foreground">
                                                                    Jam Kerja :{' '}
                                                                    {formatMinutes(
                                                                        att.work_duration_minutes,
                                                                    )}
                                                                </span>
                                                            </>
                                                        );
                                                    })()}
                                                </>
                                            )}
                                            {!isAdmin && showAbsent && (
                                                <span className="inline-flex items-center justify-center rounded-full bg-red-100 px-1.5 py-0.5 text-[10px] font-semibold text-red-700">
                                                    Tidak Hadir
                                                </span>
                                            )}
                                            {!isAdmin && dayLeaves.map((leave) => (
                                                <span
                                                    key={leave.id}
                                                    className="inline-flex items-center justify-center rounded-full bg-purple-100 px-1.5 py-0.5 text-[10px] font-semibold text-purple-700 truncate"
                                                >
                                                    Cuti
                                                </span>
                                            ))}
                                        </div>
                                    </div>
                                );
                            })}
                        </div>
                    </div>
                </Card>
            </div>

            {showCamera && (
                <CameraCapture
                    onCapture={handleCameraCapture}
                    onClose={() => setShowCamera(false)}
                />
            )}

            <Dialog
                open={!!detailAttendance}
                onOpenChange={(open) => !open && setDetailAttendance(null)}
            >
                <DialogContent>
                    <DialogHeader>
                        <DialogTitle>
                            {isAdmin && detailAttendance?.employee_name
                                ? `${detailAttendance.employee_name} - `
                                : ''}
                            {detailAttendance &&
                                format(
                                    new Date(detailAttendance.attendance_date),
                                    'dd MMMM yyyy',
                                    { locale: id },
                                )}
                        </DialogTitle>
                    </DialogHeader>
                    {detailAttendance && (
                        <div className="flex flex-col gap-4">
                            <div className="grid grid-cols-2 gap-4">
                                <div className="flex flex-col gap-2">
                                    <span className="text-sm font-medium text-muted-foreground">
                                        Foto Masuk
                                    </span>
                                    {detailAttendance.check_in_photo ? (
                                        <img
                                            src={
                                                detailAttendance.check_in_photo
                                            }
                                            alt="Foto Masuk"
                                            className="w-full rounded-lg border object-cover"
                                        />
                                    ) : (
                                        <div className="flex h-40 items-center justify-center rounded-lg border bg-muted text-sm text-muted-foreground">
                                            Tidak ada foto
                                        </div>
                                    )}
                                    <div className="flex items-center gap-2 text-sm">
                                        <LogIn className="h-4 w-4 text-green-600" />
                                        <span className="font-medium">
                                            {formatTime(
                                                detailAttendance.check_in_at,
                                            )}
                                        </span>
                                    </div>
                                </div>
                                <div className="flex flex-col gap-2">
                                    <span className="text-sm font-medium text-muted-foreground">
                                        Foto Pulang
                                    </span>
                                    {detailAttendance.check_out_photo ? (
                                        <img
                                            src={
                                                detailAttendance.check_out_photo
                                            }
                                            alt="Foto Pulang"
                                            className="w-full rounded-lg border object-cover"
                                        />
                                    ) : (
                                        <div className="flex h-40 items-center justify-center rounded-lg border bg-muted text-sm text-muted-foreground">
                                            Tidak ada foto
                                        </div>
                                    )}
                                    <div className="flex items-center gap-2 text-sm">
                                        {detailAttendance.check_out_at ? (
                                            <>
                                                <LogOut className="h-4 w-4 text-blue-600" />
                                                <span className="font-medium">
                                                    {formatTime(
                                                        detailAttendance.check_out_at,
                                                    )}
                                                </span>
                                            </>
                                        ) : (
                                            <>
                                                <Clock className="h-4 w-4 text-orange-500" />
                                                <span className="font-medium text-orange-600">
                                                    Belum pulang
                                                </span>
                                            </>
                                        )}
                                    </div>
                                </div>
                            </div>
                            <div className="flex flex-col gap-4">
                                <div className="flex flex-col gap-2">
                                    <span className="text-sm font-medium text-muted-foreground">
                                        Lokasi Masuk
                                    </span>
                                    <LocationMap
                                        latitude={
                                            detailAttendance.check_in_latitude
                                        }
                                        longitude={
                                            detailAttendance.check_in_longitude
                                        }
                                        height="200px"
                                    />
                                </div>
                                {detailAttendance.check_out_latitude && detailAttendance.check_out_longitude && (
                                    <div className="flex flex-col gap-2">
                                        <span className="text-sm font-medium text-muted-foreground">
                                            Lokasi Pulang
                                        </span>
                                        <LocationMap
                                            latitude={
                                                detailAttendance.check_out_latitude
                                            }
                                            longitude={
                                                detailAttendance.check_out_longitude
                                            }
                                            height="200px"
                                        />
                                    </div>
                                )}
                            </div>
                        </div>
                    )}
                </DialogContent>
            </Dialog>
        </>
    );
}
