<script lang="ts">
    import { supabase } from "$lib/supabaseClient";
    import { onMount } from "svelte";
    import { v4 as uuidv4 } from "uuid";
    import * as XLSX from "xlsx";

    type Timesheets = {
        id: number;
        entered_by: string;
        entered_name?: string;
        work_description: string;
        type_of_work: "Running" | "Periodic" | "Irregular";
        category_of_work:
            | "Cleaning"
            | "Gardening/Pool"
            | "Maintenance"
            | "Supervision"
            | "Guest Service"
            | "Administration"
            | "Non Billable";
        villa_id: string;
        datetime_in: string;
        datetime_out: string;
        total_work_hour: number;
        remarks: string;
        approval: boolean;
        approved_by?: string;
        approved_name?: string;
        approved_date?: Date;
        created_at?: Date;
    };
    type TimesheetsJoined = Timesheets & {
        vb_employee: { id: string; employee_name: string } | null;
        villa_name?: string;
    };
    type TimesheetDisplay = {
        id: number;
        name: string;
        staff_id: string;
        date_in: Date;
        date_out: Date;
        type_of_work: "Running" | "Periodic" | "Irregular";
        category_of_work:
            | "Cleaning"
            | "Gardening/Pool"
            | "Maintenance"
            | "Supervision"
            | "Guest Service"
            | "Administration"
            | "Non Billable";
        villa_name?: string;
        approval: string;
        approved_by?: string;
        approved_date?: Date;
        total_hours_work: number;
        remarks: string;
        created_at?: Date;
    };
    type TimesheetsInsert = {
        entered_by: string;
        work_description: string;
        type_of_work: "Running" | "Periodic" | "Irregular";
        category_of_work:
            | "Cleaning"
            | "Gardening/Pool"
            | "Maintenance"
            | "Supervision"
            | "Guest Service"
            | "Administration"
            | "Non Billable";
        villa_id: string;
        datetime_in: string;
        datetime_out: string;
        total_work_hour: number;
        remarks: string;
        approval: boolean | null; // Allow null for new entries
    };
    type Villa = {
        id: string;
        villa_name: string;
    };
    type columns = {
        key: string;
        title: string;
    };
    type Employee = {
        id: string;
        name: string;
    };

    const categoryOfWork = [
        { label: "Cleaning", value: "Cleaning" },
        { label: "Gardening/Pool", value: "Gardening/Pool" },
        { label: "Maintenance", value: "Maintenance" },
        { label: "Supervision", value: "Supervision" },
        { label: "Guest Service", value: "Guest Service" },
        { label: "Administration", value: "Administration" },
        { label: "Non Billable", value: "Non Billable" },
    ];
    const typeOfWork = [
        { label: "Running", value: "Running" },
        { label: "Periodic", value: "Periodic" },
        { label: "Irregular", value: "Irregular" },
    ];
    const columns: columns[] = [
        { key: "villa_name", title: "Villa Name" },
        { key: "name", title: "Work Description" },
        { key: "staff_id", title: "Staff Name" },
        { key: "date_in", title: "Date In" },
        { key: "date_out", title: "Date Out" },
        { key: "type_of_work", title: "Type of Work" },
        { key: "category_of_work", title: "Category of Work" },
        { key: "approval", title: "Approval" },
        { key: "approved_by", title: "Approved By" },
        { key: "approved_date", title: "Approved/Rejected Date" },
        { key: "total_hours_work", title: "Total Hours Work" },
        { key: "remarks", title: "Remarks" },
        { key: "created_at", title: "Created At" },
        { key: "actions", title: "Actions" },
    ];
    const excludedKeys = ["id"];
    const formColumns = columns.filter(
        (col) => !excludedKeys.includes(col.key),
    );
    const typeOfWorkOptions = ["Running", "Periodic", "Irregular"];
    const categoryOptions = [
        "Cleaning",
        "Gardening/Pool",
        "Maintenance",
        "Supervision",
        "Guest Service",
        "Administration",
        "Non Billable",
    ];

    // reactive variables
    let sortColumn: string | null = "created_at";
    let sortOrder: "asc" | "desc" = "desc";
    let currentUserId: string | null = null;
    let currentVillaFilter: string | null = null;
    let currentSearchTerm: string | null = null;
    let dataVilla: Villa[] = [];
    let allRows: TimesheetDisplay[] = [];
    let totalItems = 0;
    let rowsPerPage = 10;
    let showModal = false;
    let isEditing = false;
    let currentEditingId: string | null = null;
    let newTsdata: Record<string, any> = {};
    let selectedMonth: number | null = new Date().getMonth() + 1; // 1-12
    let selectedYear: number | null = new Date().getFullYear(); // Current year
    let employees: Employee[] = [];
    let villas: Villa[] = [];
    let form = {
        entered_by: "",
        work_description: "",
        type_of_work: "Running",
        category_of_work: "Cleaning",
        villa_id: "",
        datetime_in: "",
        datetime_out: "",
        total_work_hour: 0,
        remarks: "",
        approval: null, // Default null
    };
    // Fetch initial data on mount
    onMount(async () => {
        // get current user
        const {
            data: { user },
        } = await supabase.auth.getUser();
        currentUserId = user?.id ?? null;
        // fetch employees
        const { data: empData, error: empErr } = await supabase
            .from("vb_employee")
            .select("id, employee_name")
            .eq("employee_status", "Active")
            .order("employee_name", { ascending: true });

        if (!empErr && empData) {
            employees = empData.map((e) => ({
                id: e.id,
                name: e.employee_name,
            }));
        } else {
            console.error("Failed to load employees", empErr);
        }

        // fetch villas
        const { data: villaData, error: villaErr } = await supabase
            .from("vb_villas")
            .select("id, villa_name")
            .eq("villa_status", "Active")
            .order("villa_name", { ascending: true });

        if (!villaErr && villaData) {
            dataVilla = villaData;
            villas = villaData;
        } else {
            console.error("Failed to load villas", villaErr);
        }

        fetchTimeSheets(
            currentVillaFilter,
            currentSearchTerm,
            sortColumn,
            sortOrder,
            0,
            rowsPerPage,
        );
    });
    // Reactive variables for sorting
    function toggleSort(column: string) {
        if (sortColumn === column) {
            sortOrder = sortOrder === "asc" ? "desc" : "asc";
        } else {
            sortColumn = column;
            sortOrder = "asc";
        }
        fetchTimeSheets(
            currentVillaFilter,
            currentSearchTerm,
            sortColumn,
            sortOrder,
            (currentPage - 1) * rowsPerPage,
            rowsPerPage,
        );
    }

    // Function to calculate total work hours
    function calculateTotalHours() {
        if (form.datetime_in && form.datetime_out) {
            const start = new Date(form.datetime_in);
            const end = new Date(form.datetime_out);
            const diffInMs = end.getTime() - start.getTime();
            const hours = diffInMs / (1000 * 60 * 60);
            form.total_work_hour = Math.max(Number(hours.toFixed(2)), 0);
        } else {
            form.total_work_hour = 0;
        }
    }
    // Function to go to a specific page
    function goToPage(page: number) {
        console.log("Going to page:", page);

        if (page >= 1 && page <= totalPages) currentPage = page;

        // Re-fetch timesheets with the current filters and pagination
        console.log("Fetching timesheets for page:", currentPage);

        fetchTimeSheets(
            currentVillaFilter,
            currentSearchTerm,
            sortColumn,
            sortOrder,
            (currentPage - 1) * rowsPerPage,
            rowsPerPage,
        );
    }
    // Function to open the modal for adding or editing a timesheet
    function openModal(tsdata?: Record<string, any>) {
        if (tsdata) {
            // Edit mode
            isEditing = true;
            currentEditingId = tsdata.id;

            form = {
                entered_by:
                    employees.find((e) => e.name === tsdata.staff_id)?.id || "",
                work_description: tsdata.name,
                type_of_work: tsdata.type_of_work,
                category_of_work: tsdata.category_of_work,
                villa_id:
                    villas.find((v) => v.villa_name === tsdata.villa_name)
                        ?.id || "",
                datetime_in: tsdata.date_in?.toISOString().slice(0, 16),
                datetime_out: tsdata.date_out?.toISOString().slice(0, 16),
                total_work_hour: 0,
                remarks: tsdata.remarks,
                approval: null, // leave null or bring in if editing allowed
            };
            calculateTotalHours();
        } else {
            // Add mode
            isEditing = false;
            currentEditingId = null;
            form = {
                entered_by: "",
                work_description: "",
                type_of_work: "Running",
                category_of_work: "Cleaning",
                villa_id: "",
                datetime_in: "",
                datetime_out: "",
                total_work_hour: 0,
                remarks: "",
                approval: null,
            };
        }

        showModal = true;
    }

    // Function to fetch timesheets
    async function fetchTimeSheets(
        villaIdFilter: string | null = null,
        searchTerm: string | null = null,
        sortColumn: string | null = "created_at",
        sortOrder: "asc" | "desc" = "desc",
        offset: number = 0,
        limit: number = 20,
    ) {
        const fromIndex = offset;
        const toIndex = offset + limit - 1;

        let query = supabase
            .from("vb_timesheet_data")
            .select("*", { count: "exact" })
            .order(getDBColumn(sortColumn) || "created_at", {
                ascending: sortOrder === "asc",
            })
            .range(fromIndex, toIndex);

        if (typeof searchTerm === "string" && searchTerm.length > 4) {
            // Supabase ilike only supports one column at a time, so use or for multiple columns
            query = query.or(
                `work_description.ilike.%${searchTerm}%,entered_name.ilike.%${searchTerm}%`,
            );
        }

        if (villaIdFilter) {
            query = query.eq("villa_name", villaIdFilter);
        }

        // Jalankan query
        const { data, count, error } = await query;

        console.log("Fetched timesheets:", count);

        console.log("Fetched timesheets data:", data);

        if (error) {
            console.error("Error fetching timesheets:", error);
            return;
        }

        allRows = data.map((tsdata: TimesheetsJoined) => {
            return {
                id: tsdata.id,
                name: tsdata.work_description,
                staff_id: tsdata.entered_name || "Unknown Staff",
                date_in: new Date(tsdata.datetime_in),
                date_out: new Date(tsdata.datetime_out),
                type_of_work: tsdata.type_of_work,
                category_of_work: tsdata.category_of_work,
                villa_name: tsdata.villa_name || "Unknown Villa",
                approval:
                    tsdata.approval == null
                        ? "PENDING"
                        : tsdata.approval
                          ? "APPROVED"
                          : "REJECTED",
                total_hours_work:
                    Math.abs(
                        new Date(tsdata.datetime_out).getTime() -
                            new Date(tsdata.datetime_in).getTime(),
                    ) /
                    (1000 * 60 * 60),
                approved_by: tsdata.approved_name?.trim()
                    ? tsdata.approved_name
                    : tsdata.approval === true
                      ? "Auto Approve"
                      : "Not Approved",
                approved_date: tsdata.approved_date
                    ? new Date(tsdata.approved_date)
                    : undefined,
                remarks: tsdata.remarks || "No remarks",
                created_at: tsdata.created_at
                    ? new Date(tsdata.created_at)
                    : undefined,
            } as TimesheetDisplay;
        });

        totalItems = count || 0;
    }

    $: totalPages = Math.ceil(totalItems / rowsPerPage);
    $: currentPage = 1;

    function pageRange(
        totalPages: number,
        currentPage: number,
    ): (number | string)[] {
        const range: (number | string)[] = [];
        const maxDisplay = 5;

        if (totalPages <= maxDisplay + 2) {
            for (let i = 1; i <= totalPages; i++) range.push(i);
        } else {
            const start = Math.max(2, currentPage - 2);
            const end = Math.min(totalPages - 1, currentPage + 2);

            range.push(1);
            if (start > 2) range.push("...");

            for (let i = start; i <= end; i++) {
                range.push(i);
            }

            if (end < totalPages - 1) range.push("...");
            range.push(totalPages);
        }

        return range;
    }

    function getDBColumn(key: string) {
        switch (key) {
            case "name":
                return "work_description";
            case "staff_id":
                return "entered_by";
            default:
                return key;
        }
    }
    function changePage(page: number) {
        if (page < 1 || page > totalPages || page === currentPage) return;
        currentPage = page;
        fetchTimeSheets(
            currentVillaFilter,
            currentSearchTerm,
            sortColumn,
            sortOrder,
            (currentPage - 1) * rowsPerPage,
            rowsPerPage,
        );
    }

    async function exportTimesheets() {
        if (!selectedMonth || !selectedYear) {
            alert("Please select a month and year to export.");
            return;
        }

        try {
            const response = await fetch(
                "https://flow.catalis.app/webhook-test/villabugis-timesheets",
                {
                    method: "PATCH",
                    headers: {
                        "Content-Type": "application/json",
                    },
                    body: JSON.stringify({
                        month: selectedMonth,
                        year: selectedYear,
                    }),
                },
            );

            if (!response.ok) {
                throw new Error(`Export failed: ${response.statusText}`);
            }

            const randomUuid = uuidv4().toString();

            // Jika response adalah file (application/octet-stream atau Excel)
            const blob = await response.blob();
            const url = window.URL.createObjectURL(blob);
            const link = document.createElement("a");
            link.href = url;
            link.download = `timesheet-${selectedYear}-${String(selectedMonth).padStart(2, "0")}-${randomUuid}.xlsx`;
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            window.URL.revokeObjectURL(url);
        } catch (error) {
            console.error("Export error:", error);
            alert("Failed to export timesheet.");
        }
    }
    async function exportToExcelFromFrontend() {
        if (!selectedMonth || !selectedYear) {
            alert("Please select both month and year");
            return;
        }

        const startDate = new Date(selectedYear, selectedMonth - 1, 1);
        const endDate = new Date(selectedYear, selectedMonth, 0, 23, 59, 59);

        // 1. Fetch timesheet data
        const { data: timesheetData, error: timesheetErr } = await supabase
            .from("vb_timesheet_data")
            .select(
                `
                id,
                work_description,
                total_work_hour,
                type_of_work,
                category_of_work,
                approval,
                datetime_in,
                datetime_out,
                remarks,
                approved_date,
                villa_name,
                entered_name,
                approved_name
            `,
            )
            .gte("datetime_in", startDate.toISOString())
            .lte("datetime_in", endDate.toISOString());

        if (timesheetErr) {
            console.error("Error fetching timesheet:", timesheetErr);
            alert("Failed to fetch timesheet data.");
            return;
        }

        // 2. Fetch active villas
        const { data: villaData, error: villaErr } = await supabase
            .from("vb_villas")
            .select("villa_name")
            .eq("villa_status", "Active");

        if (villaErr) {
            console.error("Error fetching villas:", villaErr);
            alert("Failed to fetch villas.");
            return;
        }

        const categoryHeaders = [
            "Cleaning",
            "Gardening/Pool",
            "Maintenance",
            "Supervision",
            "Guest Service",
            "Administration",
            "Non Billable",
        ];

        const sheet2Name = "Data";
        const ws2 = XLSX.utils.json_to_sheet(timesheetData || []);

        // 3. Build Sheet1 rows
        const sheet1Rows: any[][] = [];

        // A1:B1 → Period label
        const periodText = `${startDate.toLocaleString("default", { month: "short" })}/${selectedYear}`;
        sheet1Rows.push(["Period", periodText]);

        // A2:I2 → Headers
        const headers = ["Villa Name", ...categoryHeaders, "TOTAL"];
        sheet1Rows.push(headers);

        // A3:A(n) → Villa rows
        villaData?.forEach((villa, idx) => {
            const excelRow = idx + 3; // Excel row number
            const row: any[] = [villa.villa_name];

            // B–H formulas
            categoryHeaders.forEach((cat, catIdx) => {
                const colLetter = String.fromCharCode(66 + catIdx); // 'B' = 66
                const formula = `SUMIFS(${sheet2Name}!$C:$C, ${sheet2Name}!$K:$K, $A${excelRow}, ${sheet2Name}!$E:$E, ${colLetter}$2, ${sheet2Name}!$F:$F, TRUE)`;
                row.push({ f: formula });
            });

            // I column (TOTAL)
            row.push({ f: `SUM(B${excelRow}:H${excelRow})` });

            sheet1Rows.push(row);
        });

        // Horizontal summary beside the villa table
        const headerRowIdx = 1;
        const officeRowIdx = 2;
        const fbRowIdx = 3;
        const villasOnlyRowIdx = 4;

        const ensureCols = (row: any[], length: number) => {
            while (row.length < length) row.push(null);
            return row;
        };

        [headerRowIdx, officeRowIdx, fbRowIdx, villasOnlyRowIdx].forEach(
            (idx) => {
                sheet1Rows[idx] = sheet1Rows[idx] || [];
                ensureCols(sheet1Rows[idx], 13); // at least to column M
            },
        );

        // Insert labels and formulas
        sheet1Rows[headerRowIdx][10] = "Total Work Hours"; // K2
        sheet1Rows[headerRowIdx][11] = { f: `SUM(${sheet2Name}!$C:$C)` }; // L2

        sheet1Rows[officeRowIdx][10] = "Office"; // K3
        sheet1Rows[officeRowIdx][11] = {
            f: `SUMIFS(${sheet2Name}!$C:$C, ${sheet2Name}!$K:$K, K3)`,
        }; // L3

        sheet1Rows[fbRowIdx][10] = "FB"; // K4
        sheet1Rows[fbRowIdx][11] = {
            f: `SUMIFS(${sheet2Name}!$C:$C, ${sheet2Name}!$K:$K, K4)`,
        }; // L4

        sheet1Rows[villasOnlyRowIdx][10] = "Villas Only"; // K5
        sheet1Rows[villasOnlyRowIdx][11] = { f: `L2-L3` }; // L5

        // Convert to worksheet
        const ws1 = XLSX.utils.aoa_to_sheet(sheet1Rows);

        // Bold header row (A2:I2)
        for (let c = 0; c <= headers.length; c++) {
            const cellRef = XLSX.utils.encode_cell({ r: 1, c });
            if (ws1[cellRef]) {
                ws1[cellRef].s = { font: { bold: true } };
            }
        }

        // 4. Build Workbook
        const wb = XLSX.utils.book_new();
        XLSX.utils.book_append_sheet(wb, ws1, "Summary");
        XLSX.utils.book_append_sheet(wb, ws2, sheet2Name);

        // 5. Export
        const filename = `timesheet_${selectedYear}-${String(selectedMonth).padStart(2, "0")}.xlsx`;
        XLSX.writeFile(wb, filename);
    }
    // Function to delete a timesheet
    async function deleteTimesheet(id: string) {
        if (confirm("Are you sure you want to delete this Timesheet?")) {
            const { error } = await supabase
                .from("vb_timesheet")
                .delete()
                .eq("id", id);
            if (error) {
                console.error("Error deleting Timesheet:", error);
                return;
            }
            await fetchTimeSheets(
                currentVillaFilter,
                currentSearchTerm,
                sortColumn,
                sortOrder,
                (currentPage - 1) * rowsPerPage,
                rowsPerPage,
            );
        }
    }
    // Function to update the approval status of a timesheet
    async function updateApprovalStatus(
        id: string,
        status: string,
    ): Promise<void> {
        const approved = status === "true";
        const approved_by = currentUserId;
        const approved_date = new Date().toISOString();
        const { error } = await supabase
            .from("vb_timesheet")
            .update({
                approval: status,
                approved_by,
                approved_date,
            })
            .eq("id", id);

        if (error) {
            console.error("Error updating approval status:", error);
        } else {
            await fetchTimeSheets(
                currentVillaFilter,
                currentSearchTerm,
                sortColumn,
                sortOrder,
                (currentPage - 1) * rowsPerPage,
                rowsPerPage,
            );
        }
    }
    // Function to submit the form data
    async function submitForm() {
        calculateTotalHours();

        if (!form.entered_by || !form.villa_id) {
            alert("Please select an employee and villa.");
            return;
        }

        let error = null;

        if (isEditing && currentEditingId) {
            const { error: updateError } = await supabase
                .from("vb_timesheet")
                .update({
                    entered_by: form.entered_by,
                    work_description: form.work_description,
                    type_of_work: form.type_of_work,
                    category_of_work: form.category_of_work,
                    villa_id: form.villa_id,
                    datetime_in: form.datetime_in,
                    datetime_out: form.datetime_out,
                    total_work_hour: form.total_work_hour,
                    remarks: form.remarks,
                    approval: form.approval,
                })
                .eq("id", currentEditingId);

            error = updateError;
        } else {
            form = {
                ...form,
                entered_by: form.entered_by,
                work_description: form.work_description,
                type_of_work: form.type_of_work,
                category_of_work: form.category_of_work,
                villa_id: form.villa_id,
                datetime_in: form.datetime_in,
                datetime_out: form.datetime_out,
                total_work_hour: form.total_work_hour,
                remarks: form.remarks,
                approval: form.approval || null, // Allow null for new entries
            };

            const { error: insertError } = await supabase
                .from("vb_timesheet")
                .insert([form]);

            error = insertError;
        }

        if (error) {
            alert("Failed to save timesheets: " + error.message);
        } else {
            alert("Timesheet saved successfully!");
            form = {
                entered_by: "",
                work_description: "",
                type_of_work: "Running",
                category_of_work: "Cleaning",
                villa_id: "",
                datetime_in: "",
                datetime_out: "",
                total_work_hour: 0,
                remarks: "",
                approval: null,
            };
            await fetchTimeSheets(
                currentVillaFilter,
                currentSearchTerm,
                sortColumn,
                sortOrder,
                (currentPage - 1) * rowsPerPage,
                rowsPerPage,
            );
            showModal = false;
        }
    }
</script>

<div>
    <div
        class="p-6 bg-white shadow-md rounded-2xl mb-4 flex flex-col sm:flex-row sm:justify-between sm:items-center gap-4"
    >
        <div>
            <h2 class="text-lg font-semibold text-gray-800">
                🕒 Timesheet List
            </h2>
            <p class="text-sm text-gray-600">
                Manage and track timesheets for staff members.
            </p>
        </div>
        <div class="flex flex-col sm:flex-row sm:items-center gap-2">
            <input
                type="text"
                id="search-input"
                placeholder="🔍 Search by work description or name..."
                class="border border-gray-300 focus:ring-2 focus:ring-blue-500 focus:outline-none px-4 py-2 rounded-xl text-sm w-64 transition"
                on:input={(e) => {
                    currentSearchTerm = (
                        e.target as HTMLInputElement
                    ).value.toLowerCase();
                    fetchTimeSheets(currentVillaFilter, currentSearchTerm);
                }}
            />
            <select
                id="villa-select"
                class="border border-gray-300 focus:ring-2 focus:ring-blue-500 focus:outline-none px-4 py-2 rounded-xl text-sm w-48 transition"
                on:change={(e) => {
                    currentVillaFilter =
                        (e.target as HTMLSelectElement).value || null;
                    fetchTimeSheets(currentVillaFilter, currentSearchTerm);
                }}
            >
                <option value="">All Villa</option>
                {#each dataVilla as villa}
                    <option value={villa.villa_name}>{villa.villa_name}</option>
                {/each}
            </select>
            <button
                class="bg-gray-200 text-gray-700 px-4 py-2 rounded-xl hover:bg-gray-300 text-sm transition"
                on:click={() => {
                    currentVillaFilter = null;
                    currentSearchTerm = null;

                    // Optional: reset UI elements if you use bind:value
                    const searchInput = document.querySelector(
                        "#search-input",
                    ) as HTMLInputElement;
                    if (searchInput) searchInput.value = "";

                    const villaSelect = document.querySelector(
                        "#villa-select",
                    ) as HTMLSelectElement;
                    if (villaSelect) villaSelect.value = "";

                    fetchTimeSheets(null, null);
                }}
            >
                🔄 Reset
            </button>
            <button
                class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 text-sm"
                on:click={() => openModal()}
            >
                ➕ Add Timesheet
            </button>
        </div>
    </div>
    <div class="overflow-x-auto rounded-lg shadow mb-4 max-h-[70vh]">
        <table class="min-w-[1000px] divide-y divide-gray-200 text-sm w-max">
            <thead class="bg-gray-100">
                <tr>
                    {#each columns as col}
                        {#if col.key === "villa_name"}
                            <th
                                class="sticky left-0 px-4 py-3 text-left font-semibold text-gray-700 uppercase tracking-wider whitespace-nowrap"
                                style="background-color: #f0f8ff; z-index: 10;"
                                on:click={() => toggleSort(col.key)}
                            >
                                {col.title}
                                {#if sortColumn === col.key}
                                    {sortOrder === "asc" ? " 🔼" : " 🔽"}
                                {/if}
                            </th>
                        {:else}
                            <th
                                class="cursor-pointer px-4 py-3 text-left font-semibold text-gray-700 uppercase tracking-wider whitespace-nowrap"
                                on:click={() => toggleSort(col.key)}
                            >
                                {col.title}
                                {#if sortColumn === col.key}
                                    {sortOrder === "asc" ? " 🔼" : " 🔽"}
                                {/if}
                            </th>
                        {/if}
                    {/each}
                </tr>
            </thead>
            <tbody class="divide-y divide-gray-200 bg-white text-align-top">
                {#each allRows as row}
                    <tr class="hover:bg-gray-50 transition">
                        {#each columns as col}
                            {#if col.key === "name"}
                                <td
                                    class="left-0 px-4 py-2 max-w-xs whitespace-normal break-words"
                                >
                                    {row[col.key]}
                                </td>
                            {:else if col.key === "approval"}
                                <td class="px-4 py-2 align-top">
                                    <span
                                        class="inline-flex items-center gap-1 rounded px-2 py-1 text-xs font-medium
                                            {row[col.key] === 'APPROVED'
                                            ? 'bg-green-100 text-green-800'
                                            : 'bg-yellow-100 text-yellow-800'}"
                                    >
                                        {row[col.key]}
                                    </span>
                                    {#if row.approval === "PENDING"}
                                        <button
                                            class="ml-2 inline-flex items-center gap-1 rounded bg-green-600 px-3 py-1.5 text-white text-xs font-medium hover:bg-green-700"
                                            on:click={() =>
                                                updateApprovalStatus(
                                                    String(row.id),
                                                    "true",
                                                )}
                                        >
                                            ✅ Approve
                                        </button>
                                        <button
                                            class="ml-2 inline-flex items-center gap-1 rounded bg-red-600 px-3 py-1.5 text-white text-xs font-medium hover:bg-red-700"
                                            on:click={() =>
                                                updateApprovalStatus(
                                                    String(row.id),
                                                    "false",
                                                )}
                                        >
                                            ❌ Reject
                                        </button>
                                    {/if}
                                </td>
                            {:else if col.key === "approved_by"}
                                <td class="px-4 py-2 align-text-top">
                                    {row[col.key] || "Not Approved"}
                                </td>
                            {:else if col.key === "approved_date"}
                                <td class="px-4 py-2">
                                    {row[col.key] &&
                                    !isNaN(
                                        new Date(
                                            row[col.key] as
                                                | string
                                                | number
                                                | Date,
                                        ).getTime(),
                                    )
                                        ? new Date(
                                              row[col.key] as
                                                  | string
                                                  | number
                                                  | Date,
                                          ).toLocaleString()
                                        : "N/A"}
                                </td>
                            {:else if col.key === "total_hours_work"}
                                <td class="px-4 py-2">
                                    {row[col.key].toFixed(2)} hours
                                </td>
                            {:else if col.key === "created_at"}
                                <td class="px-4 py-2">
                                    {row[col.key] !== undefined
                                        ? new Date(
                                              row[col.key] as
                                                  | string
                                                  | number
                                                  | Date,
                                          ).toLocaleString()
                                        : "N/A"}
                                </td>
                            {:else if col.key === "villa_name"}
                                <td
                                    class="sticky left-0 px-4 py-2 font-medium text-blue-600 max-w-xs whitespace-normal align-top break-words"
                                    style="background-color: #f0f8ff; cursor: pointer;"
                                >
                                    {row[col.key] || "Unknown Villa"}
                                </td>
                            {:else if col.key === "staff_id"}
                                <td class="px-4 py-2">
                                    {row[col.key] || "Unknown Staff"}
                                </td>
                            {:else if col.key === "remarks"}
                                <td class="px-4 py-2">
                                    {row[col.key] || "No remarks"}
                                </td>
                            {:else if col.key === "actions"}
                                <td class="px-4 py-2">
                                    <button
                                        class="inline-flex items-center gap-1 rounded bg-blue-600 px-3 py-1.5 text-white text-xs font-medium hover:bg-blue-700"
                                        on:click={() => openModal(row)}
                                    >
                                        ✏️ Edit
                                    </button>
                                    <button
                                        class="inline-flex items-center gap-1 rounded bg-red-600 px-3 py-1.5 text-white text-xs font-medium hover:bg-red-700"
                                        on:click={() =>
                                            deleteTimesheet(String(row.id))}
                                    >
                                        🗑️ Delete
                                    </button>
                                </td>
                            {:else if col.key === "date_in" || col.key === "date_out"}
                                <td class="px-4 py-2">
                                    {row[col.key]
                                        ? new Date(
                                              row[col.key],
                                          ).toLocaleString()
                                        : "N/A"}
                                </td>
                            {:else}
                                <td class="px-4 py-2">
                                    {row[col.key as keyof TimesheetDisplay]}
                                </td>
                            {/if}
                        {/each}
                    </tr>
                {/each}
            </tbody>
        </table>
    </div>

    <!-- Pagination controls -->
    <div class="flex justify-between items-center text-sm">
        <div>
            Showing {(currentPage - 1) * rowsPerPage + 1}–
            {Math.min(currentPage * rowsPerPage, totalItems)} of {totalItems} items
        </div>
        <div class="flex items-center space-x-4">
            <!-- Export Controls -->
            <div class="">
                <!-- Month Selector -->
                <label for="month" class="text-sm">Month:</label>
                <select
                    id="month"
                    class="border border-gray-300 px-2 py-1 rounded text-sm"
                    bind:value={selectedMonth}
                >
                    <option value="" disabled selected>Select</option>
                    {#each Array.from({ length: 12 }, (_, i) => i + 1) as m}
                        <option value={m}>{m}</option>
                    {/each}
                </select>

                <!-- Year Selector -->
                <label for="year" class="text-sm ml-2">Year:</label>
                <select
                    id="year"
                    class="border border-gray-300 px-2 py-1 rounded text-sm"
                    bind:value={selectedYear}
                >
                    <option value="" disabled selected>Select</option>
                    {#each Array.from({ length: 5 }, (_, i) => new Date().getFullYear() - i) as y}
                        <option value={y}>{y}</option>
                    {/each}
                </select>

                <!-- Export Button -->
                <button
                    class="bg-green-600 text-white px-3 py-1 rounded hover:bg-green-700 text-sm"
                    on:click={exportToExcelFromFrontend}
                >
                    ⬇️ Export
                </button>
            </div>
            <div class="space-x-2">
                <label for="rowsPerPage" class="text-sm">Rows per page:</label>
                <select
                    id="rowsPerPage"
                    class="border border-gray-300 px-2 py-1 rounded text-sm"
                    bind:value={rowsPerPage}
                    on:change={() => {
                        currentPage = 1; // Reset to first page on change
                        fetchTimeSheets(
                            currentVillaFilter,
                            currentSearchTerm,
                            sortColumn,
                            sortOrder,
                            0,
                            rowsPerPage,
                        );
                    }}
                >
                    {#each [10, 20, 50, 100] as option}
                        <option value={option}>{option}</option>
                    {/each}
                </select>
                <button
                    class="px-3 py-1 rounded border border-gray-300 bg-white hover:bg-gray-100 disabled:opacity-50"
                    on:click={() => goToPage(currentPage - 1)}
                    disabled={currentPage === 1}
                >
                    Previous
                </button>
                {#each pageRange(totalPages, currentPage) as page}
                    {#if page === "..."}
                        <span class="px-2">...</span>
                    {:else}
                        <button
                            on:click={() => changePage(page as number)}
                            class="px-2 py-1 border rounded {page ===
                            currentPage
                                ? 'bg-blue-600 text-white border-blue-600'
                                : 'bg-white border-gray-300 hover:bg-gray-100'}"
                        >
                            {page}
                        </button>
                    {/if}
                {/each}
                <button
                    class="px-3 py-1 rounded border border-gray-300 bg-white hover:bg-gray-100 disabled:opacity-50"
                    on:click={() => goToPage(currentPage + 1)}
                    disabled={currentPage === totalPages}
                >
                    Next
                </button>
            </div>
        </div>
    </div>
</div>

<!-- Modal -->
{#if showModal}
    <div
        class="fixed inset-0 bg-black bg-opacity-50 z-50 overflow-y-auto py-10 px-4 flex justify-center items-start"
    >
        <form
            on:submit|preventDefault={submitForm}
            class="w-full max-w-lg bg-white p-6 rounded-2xl shadow-xl space-y-4"
        >
            <div class="flex justify-between items-center mb-4">
                <h2 class="text-xl font-semibold">
                    {isEditing ? "Edit Timesheet" : "New Timesheet Entry"}
                </h2>
                <button
                    type="button"
                    class="text-gray-500 hover:text-gray-700"
                    on:click={() => (showModal = false)}
                >
                    ✖️
                </button>
            </div>

            <div>
                <label for="t_eb" class="block text-sm font-medium mb-1"
                    >Entered By</label
                >
                <select
                    id="t_eb"
                    class="w-full border p-2 rounded"
                    bind:value={form.entered_by}
                    required
                >
                    <option value="" disabled selected>Select Employee</option>
                    {#each employees as employee}
                        <option value={employee.id}>{employee.name}</option>
                    {/each}
                </select>
            </div>

            <div>
                <label for="t_wd" class="block text-sm font-medium mb-1"
                    >Work Description</label
                >
                <textarea
                    id="t_wd"
                    class="w-full border border-gray-300 p-2 rounded"
                    bind:value={form.work_description}
                    placeholder="Describe the work"
                    required
                ></textarea>
            </div>

            <div>
                <label for="t_ow" class="block text-sm font-medium mb-1"
                    >Type of Work</label
                >
                <select
                    id="t_ow"
                    class="w-full border p-2 rounded"
                    bind:value={form.type_of_work}
                >
                    {#each typeOfWorkOptions as option}
                        <option value={option}>{option}</option>
                    {/each}
                </select>
            </div>

            <div>
                <label for="t_cow" class="block text-sm font-medium mb-1"
                    >Category of Work</label
                >
                <select
                    id="t_cow"
                    class="w-full border p-2 rounded"
                    bind:value={form.category_of_work}
                >
                    {#each categoryOptions as option}
                        <option value={option}>{option}</option>
                    {/each}
                </select>
            </div>

            <div>
                <label for="t_vn" class="block text-sm font-medium mb-1"
                    >Villa</label
                >
                <select
                    id="t_vn"
                    class="w-full border p-2 rounded"
                    bind:value={form.villa_id}
                    required
                >
                    <option value="" disabled selected>Select Villa</option>
                    {#each villas as villa}
                        <option value={villa.id}>{villa.villa_name}</option>
                    {/each}
                </select>
            </div>

            <div>
                <label for="tdto" class="block text-sm font-medium mb-1"
                    >Date/Time In</label
                >
                <input
                    id="tdto"
                    type="datetime-local"
                    class="w-full border p-2 rounded"
                    bind:value={form.datetime_in}
                    on:change={calculateTotalHours}
                    required
                />
            </div>

            <div>
                <label for="dto" class="block text-sm font-medium mb-1"
                    >Date/Time Out</label
                >
                <input
                    id="dto"
                    type="datetime-local"
                    class="w-full border p-2 rounded"
                    bind:value={form.datetime_out}
                    on:change={calculateTotalHours}
                    required
                />
            </div>

            <div class="text-sm">
                <label for="ttwo" class="block font-medium mb-1"
                    >Total Work Hours</label
                >
                <div id="ttwo" class="px-3 py-2">{form.total_work_hour}</div>
            </div>

            <div>
                <label for="trmk" class="block text-sm font-medium mb-1"
                    >Remarks</label
                >
                <textarea
                    id="trmk"
                    class="w-full border border-gray-300 p-2 rounded"
                    bind:value={form.remarks}
                    placeholder="Optional remarks"
                ></textarea>
            </div>

            <button
                type="submit"
                class="w-full bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 transition"
            >
                {isEditing ? "Update Timesheet" : "New Entry"}
            </button>
        </form>
    </div>
{/if}
