import { Head, Link, router } from '@inertiajs/react';
import { createColumnHelper } from '@tanstack/react-table';
import type { ColumnDef, PaginationState, SortingState } from '@tanstack/react-table';
import { CalendarCheck, Clock, Eye, Plus, UserX } from 'lucide-react';
import type { LucideIcon } from 'lucide-react';
import { useEffect, useMemo, useRef, useState } from 'react';
import {
    DataTable,
    DataTableColumnHeader,
} from '@/components/data-table';
import Heading from '@/components/heading';
import { Button } from '@/components/ui/button';
import {
    Select,
    SelectContent,
    SelectItem,
    SelectTrigger,
    SelectValue,
} from '@/components/ui/select';
import { cn, formatDate } from '@/lib/utils';
import { useCan } from '@/hooks/use-can';
import { dashboard } from '@/routes';
import { index, show } from '@/routes/admin/leave-requests';
import type { Paginated } from '@/types';
import type { BalanceOption } from './leave-request-form';
import { LeaveRequestFormModal } from './leave-request-form-modal';
import { LeaveStatusBadge } from './status-badge';

type LeaveRequestRow = {
    id: number;
    code: string;
    start_date: string;
    end_date: string;
    days: number;
    status: string;
    status_label: string;
    reason: string | null;
    employee: { id: number; code: string; full_name: string };
    leave_type: { id: number; name: string; code: string };
    created_at: string | null;
};

type Option = { value: string; label: string };
type LeaveTypeOption = {
    id: number;
    name: string;
    code: string;
    deducts_balance: boolean;
};
type EmployeeOption = { id: number; code: string; full_name: string };

type LeaveStats = {
    pending: number;
    absent_today: number;
    approved_this_month: number;
};

type StatCard = {
    key: string;
    label: string;
    value: number;
    icon: LucideIcon;
    tone?: 'default' | 'warning';
    onClick: () => void;
};

type Filters = {
    search: string;
    status: string;
    leave_type_id: number | null;
    employee_id: number | null;
    from: string;
    to: string;
    sort: string;
    direction: 'asc' | 'desc';
    per_page: number;
};

type DateRangePreset =
    | 'all'
    | 'today'
    | 'this_week'
    | 'this_month'
    | 'last_month'
    | 'custom';

const DATE_RANGE_OPTIONS: { value: Exclude<DateRangePreset, 'custom'>; label: string }[] = [
    { value: 'all', label: 'Toutes les dates' },
    { value: 'today', label: "Aujourd'hui" },
    { value: 'this_week', label: 'Cette semaine' },
    { value: 'this_month', label: 'Ce mois' },
    { value: 'last_month', label: 'Mois dernier' },
];

const columnHelper = createColumnHelper<LeaveRequestRow>();

function toDateInputValue(date: Date): string {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');

    return `${year}-${month}-${day}`;
}

function startOfWeek(date: Date): Date {
    const result = new Date(date.getFullYear(), date.getMonth(), date.getDate());
    const day = result.getDay();
    const diff = day === 0 ? -6 : 1 - day;
    result.setDate(result.getDate() + diff);

    return result;
}

function resolveDateRange(preset: Exclude<DateRangePreset, 'custom'>): {
    from: string;
    to: string;
} {
    const now = new Date();
    const today = toDateInputValue(now);

    if (preset === 'all') {
        return { from: '', to: '' };
    }

    if (preset === 'today') {
        return { from: today, to: today };
    }

    if (preset === 'this_week') {
        const weekStart = startOfWeek(now);
        const weekEnd = new Date(weekStart);
        weekEnd.setDate(weekStart.getDate() + 6);

        return {
            from: toDateInputValue(weekStart),
            to: toDateInputValue(weekEnd),
        };
    }

    if (preset === 'this_month') {
        return {
            from: toDateInputValue(new Date(now.getFullYear(), now.getMonth(), 1)),
            to: toDateInputValue(new Date(now.getFullYear(), now.getMonth() + 1, 0)),
        };
    }

    return {
        from: toDateInputValue(new Date(now.getFullYear(), now.getMonth() - 1, 1)),
        to: toDateInputValue(new Date(now.getFullYear(), now.getMonth(), 0)),
    };
}

function detectDateRange(from: string, to: string): DateRangePreset {
    if (!from && !to) {
        return 'all';
    }

    for (const option of DATE_RANGE_OPTIONS) {
        if (option.value === 'all') {
            continue;
        }

        const range = resolveDateRange(option.value);

        if (range.from === from && range.to === to) {
            return option.value;
        }
    }

    return 'custom';
}

function formatDayLabel(value: string): string {
    return new Intl.DateTimeFormat('fr-FR', {
        day: '2-digit',
        month: 'short',
        year: 'numeric',
    }).format(new Date(`${value}T12:00:00`));
}

function dateRangeLabel(from: string, to: string): string {
    if (from && to) {
        return `${formatDayLabel(from)} – ${formatDayLabel(to)}`;
    }

    if (from) {
        return `À partir du ${formatDayLabel(from)}`;
    }

    if (to) {
        return `Jusqu'au ${formatDayLabel(to)}`;
    }

    return 'Toutes les dates';
}

function visitLeaveRequests(params: {
    search: string;
    status: string;
    leave_type_id: string;
    from: string;
    to: string;
    sort: string;
    direction: 'asc' | 'desc';
    page: number;
    per_page: number;
}) {
    router.get(
        index.url(),
        {
            search: params.search || undefined,
            status: params.status || undefined,
            leave_type_id:
                params.leave_type_id && params.leave_type_id !== 'all'
                    ? params.leave_type_id
                    : undefined,
            from: params.from || undefined,
            to: params.to || undefined,
            sort: params.sort,
            direction: params.direction,
            page: params.page > 1 ? params.page : undefined,
            per_page: params.per_page !== 15 ? params.per_page : undefined,
        },
        { preserveState: true, replace: true, preserveScroll: true },
    );
}

export default function LeaveRequestsIndex({
    leaveRequests,
    filters,
    statuses,
    leaveTypes,
    canCreate,
    stats,
    createEmployees,
    createBalances,
    createDefaultEmployeeId,
}: {
    leaveRequests: Paginated<LeaveRequestRow>;
    filters: Filters;
    statuses: Option[];
    leaveTypes: LeaveTypeOption[];
    canCreate: boolean;
    stats: LeaveStats | null;
    createEmployees: EmployeeOption[];
    createBalances: BalanceOption[];
    createDefaultEmployeeId: number | null;
}) {
    const canCreateLeave = useCan('leave.create') && canCreate;
    const isFirstSearchEffect = useRef(true);
    const [isLoading, setIsLoading] = useState(false);
    const [createOpen, setCreateOpen] = useState(false);
    const [search, setSearch] = useState(filters.search);
    const [status, setStatus] = useState(filters.status || 'all');
    const [leaveTypeId, setLeaveTypeId] = useState(
        filters.leave_type_id ? String(filters.leave_type_id) : 'all',
    );
    const [dateRange, setDateRange] = useState<DateRangePreset>(() =>
        detectDateRange(filters.from, filters.to),
    );
    const [from, setFrom] = useState(filters.from);
    const [to, setTo] = useState(filters.to);
    const [sorting, setSorting] = useState<SortingState>([
        { id: filters.sort, desc: filters.direction === 'desc' },
    ]);
    const [pagination, setPagination] = useState<PaginationState>({
        pageIndex: leaveRequests.current_page - 1,
        pageSize: leaveRequests.per_page,
    });

    useEffect(() => {
        const removeStart = router.on('start', () => setIsLoading(true));
        const removeFinish = router.on('finish', () => setIsLoading(false));

        return () => {
            removeStart();
            removeFinish();
        };
    }, []);

    useEffect(() => {
        if (isFirstSearchEffect.current) {
            isFirstSearchEffect.current = false;

            return;
        }

        const timeout = window.setTimeout(() => {
            const sort = sorting[0];
            visitLeaveRequests({
                search,
                status: status === 'all' ? '' : status,
                leave_type_id: leaveTypeId,
                from,
                to,
                sort: sort?.id ?? 'created_at',
                direction: sort?.desc === false ? 'asc' : 'desc',
                page: 1,
                per_page: pagination.pageSize,
            });
        }, 300);

        return () => window.clearTimeout(timeout);
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [search, status, leaveTypeId, from, to]);

    const applyDateRange = (preset: Exclude<DateRangePreset, 'custom'>) => {
        const range = resolveDateRange(preset);
        setDateRange(preset);
        setFrom(range.from);
        setTo(range.to);
    };

    const statCards = useMemo((): StatCard[] => {
        if (!stats) {
            return [];
        }

        return [
            {
                key: 'pending',
                label: 'Demandes en attente',
                value: stats.pending,
                icon: Clock,
                tone: stats.pending > 0 ? 'warning' : 'default',
                onClick: () => {
                    setStatus('submitted');
                    applyDateRange('all');
                },
            },
            {
                key: 'absent_today',
                label: "Absents aujourd'hui",
                value: stats.absent_today,
                icon: UserX,
                onClick: () => {
                    setStatus('approved');
                    applyDateRange('today');
                },
            },
            {
                key: 'approved_this_month',
                label: 'Congés validés (Mois)',
                value: stats.approved_this_month,
                icon: CalendarCheck,
                onClick: () => {
                    setStatus('approved');
                    applyDateRange('this_month');
                },
            },
        ];
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [stats]);

    const columns = useMemo(
        () =>
            [
                columnHelper.accessor('code', {
                    header: ({ column }) => (
                        <DataTableColumnHeader column={column} title="Code" />
                    ),
                    cell: (info) => (
                        <Link
                            href={show(info.row.original.id)}
                            className="font-mono text-sm hover:underline"
                        >
                            {info.getValue()}
                        </Link>
                    ),
                }),
                columnHelper.display({
                    id: 'employee',
                    header: 'Collaborateur',
                    cell: ({ row }) => row.original.employee.full_name,
                }),
                columnHelper.display({
                    id: 'leave_type',
                    header: 'Type',
                    cell: ({ row }) => row.original.leave_type.name,
                }),
                columnHelper.accessor('start_date', {
                    header: ({ column }) => (
                        <DataTableColumnHeader column={column} title="Début" />
                    ),
                    cell: (info) => formatDate(info.getValue()),
                }),
                columnHelper.accessor('days', {
                    header: ({ column }) => (
                        <DataTableColumnHeader column={column} title="Jours" />
                    ),
                }),
                columnHelper.accessor('status', {
                    header: 'Statut',
                    enableSorting: false,
                    cell: ({ row }) => (
                        <LeaveStatusBadge
                            status={row.original.status}
                            label={row.original.status_label}
                        />
                    ),
                }),
                columnHelper.display({
                    id: 'actions',
                    header: '',
                    cell: ({ row }) => (
                        <div className="flex justify-end">
                            <Button variant="ghost" size="icon" asChild>
                                <Link href={show(row.original.id)}>
                                    <Eye />
                                </Link>
                            </Button>
                        </div>
                    ),
                }),
            ] as ColumnDef<LeaveRequestRow>[],
        [],
    );

    return (
        <>
            <Head title="Congés & absences" />
            <div className="flex h-full flex-1 flex-col gap-6 p-4 md:p-6">
                <div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
                    <Heading
                        title="Congés & absences"
                        description="Demandes, validation et suivi"
                    />
                    {canCreateLeave && (
                        <Button onClick={() => setCreateOpen(true)}>
                            <Plus />
                            Nouvelle demande
                        </Button>
                    )}
                </div>

                {statCards.length > 0 && (
                    <div className="grid gap-3 sm:grid-cols-3">
                        {statCards.map((card) => {
                            const Icon = card.icon;

                            return (
                                <button
                                    key={card.key}
                                    type="button"
                                    onClick={card.onClick}
                                    className={cn(
                                        'rounded-xl border bg-card p-4 text-left transition-colors hover:bg-muted/40',
                                        card.tone === 'warning' &&
                                            'border-amber-200/80 dark:border-amber-900/50',
                                    )}
                                >
                                    <div className="flex items-start justify-between gap-3">
                                        <div className="space-y-1">
                                            <p className="text-muted-foreground text-sm">
                                                {card.label}
                                            </p>
                                            <p className="text-2xl font-semibold tabular-nums tracking-tight">
                                                {card.value}
                                            </p>
                                        </div>
                                        <span
                                            className={cn(
                                                'flex size-9 items-center justify-center rounded-lg bg-muted text-muted-foreground',
                                                card.tone === 'warning' &&
                                                    'bg-amber-50 text-amber-700 dark:bg-amber-950/40 dark:text-amber-400',
                                            )}
                                        >
                                            <Icon className="size-4" />
                                        </span>
                                    </div>
                                </button>
                            );
                        })}
                    </div>
                )}

                <DataTable
                    id="admin-leave-requests"
                    columns={columns}
                    data={leaveRequests.data}
                    getRowId={(row) => String(row.id)}
                    isLoading={isLoading}
                    searchValue={search}
                    onSearchChange={setSearch}
                    searchPlaceholder="Rechercher…"
                    emptyMessage="Aucune demande."
                    toolbarLeft={
                        <div className="flex flex-wrap gap-2">
                            <Select value={status} onValueChange={setStatus}>
                                <SelectTrigger className="w-[180px]">
                                    <SelectValue placeholder="Statut" />
                                </SelectTrigger>
                                <SelectContent>
                                    <SelectItem value="all">
                                        Tous les statuts
                                    </SelectItem>
                                    {statuses.map((item) => (
                                        <SelectItem
                                            key={item.value}
                                            value={item.value}
                                        >
                                            {item.label}
                                        </SelectItem>
                                    ))}
                                </SelectContent>
                            </Select>
                            <Select
                                value={leaveTypeId}
                                onValueChange={setLeaveTypeId}
                            >
                                <SelectTrigger className="w-[180px]">
                                    <SelectValue placeholder="Type" />
                                </SelectTrigger>
                                <SelectContent>
                                    <SelectItem value="all">
                                        Tous les types
                                    </SelectItem>
                                    {leaveTypes.map((type) => (
                                        <SelectItem
                                            key={type.id}
                                            value={String(type.id)}
                                        >
                                            {type.name}
                                        </SelectItem>
                                    ))}
                                </SelectContent>
                            </Select>
                            <Select
                                value={dateRange}
                                onValueChange={(value) => {
                                    if (value === 'custom') {
                                        return;
                                    }

                                    applyDateRange(
                                        value as Exclude<
                                            DateRangePreset,
                                            'custom'
                                        >,
                                    );
                                }}
                            >
                                <SelectTrigger className="w-[220px]">
                                    <SelectValue placeholder="Période" />
                                </SelectTrigger>
                                <SelectContent>
                                    {DATE_RANGE_OPTIONS.map((option) => (
                                        <SelectItem
                                            key={option.value}
                                            value={option.value}
                                        >
                                            {option.label}
                                        </SelectItem>
                                    ))}
                                    {dateRange === 'custom' && (
                                        <SelectItem value="custom">
                                            {dateRangeLabel(from, to)}
                                        </SelectItem>
                                    )}
                                </SelectContent>
                            </Select>
                        </div>
                    }
                    sorting={sorting}
                    onSortingChange={(updater) => {
                        const next =
                            typeof updater === 'function'
                                ? updater(sorting)
                                : updater;
                        setSorting(next);
                        const sort = next[0];
                        visitLeaveRequests({
                            search,
                            status: status === 'all' ? '' : status,
                            leave_type_id: leaveTypeId,
                            from,
                            to,
                            sort: sort?.id ?? 'created_at',
                            direction: sort?.desc === false ? 'asc' : 'desc',
                            page: 1,
                            per_page: pagination.pageSize,
                        });
                    }}
                    manualSorting
                    pagination={pagination}
                    onPaginationChange={(updater) => {
                        const next =
                            typeof updater === 'function'
                                ? updater(pagination)
                                : updater;
                        const pageChanged =
                            next.pageIndex !== pagination.pageIndex;
                        const sizeChanged =
                            next.pageSize !== pagination.pageSize;
                        setPagination(next);
                        if (!pageChanged && !sizeChanged) {
                            return;
                        }
                        const sort = sorting[0];
                        visitLeaveRequests({
                            search,
                            status: status === 'all' ? '' : status,
                            leave_type_id: leaveTypeId,
                            from,
                            to,
                            sort: sort?.id ?? 'created_at',
                            direction: sort?.desc === false ? 'asc' : 'desc',
                            page: sizeChanged ? 1 : next.pageIndex + 1,
                            per_page: next.pageSize,
                        });
                    }}
                    manualPagination
                    pageCount={leaveRequests.last_page}
                    totalRows={leaveRequests.total}
                />
            </div>

            {canCreateLeave && (
                <LeaveRequestFormModal
                    open={createOpen}
                    onOpenChange={setCreateOpen}
                    employees={createEmployees}
                    leaveTypes={leaveTypes}
                    initialBalances={createBalances}
                    defaultEmployeeId={createDefaultEmployeeId}
                />
            )}
        </>
    );
}

LeaveRequestsIndex.layout = {
    breadcrumbs: [
        { title: 'Tableau de bord', href: dashboard() },
        { title: 'Congés & absences', href: index() },
    ],
};
