<script>
    import { useDictionaryForm } from "$lib/components/composable/use-dictionary-form.svelte";
    import FormPageContainer from "$lib/components/reusable/form/form-page-container.svelte";
    import DictionaryFormRenderer from "$lib/components/reusable/form/dictionary-form-renderer.svelte";
    import { toast } from "svelte-sonner";
    import { untrack } from "svelte";
    import { API } from "$lib/config/api";
    import ReusableAlertDialog from "$lib/components/reusable/reusable-alert-dialog.svelte";
    import { Separator } from "$lib/components/ui/separator/index.js";
    import { contactDetailSchema, contactDetailInitialForm, contactDetailDefaultErrors, contactDetailFormFields, buildContactPayload } from "$lib/components/dictionary/contact/config/contact-form-config";
    import { Button } from "$lib/components/ui/button/index.js";
    import { useForm } from "$lib/components/composable/use-form.svelte";
    import { getChangedFields } from "$lib/utils/getChangedFields";
    import * as Table from '$lib/components/ui/table/index.js';
    import PencilIcon from "@lucide/svelte/icons/pencil";
    import Trash2Icon from "@lucide/svelte/icons/trash-2";

    let props = $props();

    const { masterDetail, formFields, formActions, schema, initialForm } = props.context;

    const { formState } = masterDetail;

    let editingId = $state(null);
    let idCounter = $state(0);
    let tempDetailContact = $state([]);
    let deletedDetailIds = $state([]);

    const contactDetailFormState = useForm({
        schema: contactDetailSchema,
        initialForm: contactDetailInitialForm,
        defaultErrors: contactDetailDefaultErrors,
    });

    const helpers = useDictionaryForm(formState);

    let showConfirm = $state(false);

        function snapshotForm() {
        return untrack(() => {
            const f = contactDetailFormState.form;
            return {
                SiteID: f.SiteID ?? "",
                ContactCode: f.ContactCode ?? "",
                ContactEmail: f.ContactEmail ?? "",
                Department: f.Department ?? "",
                OccupationID: f.OccupationID ?? "",
                JobTitle: f.JobTitle ?? "",
            };
        });
    }

    function resetContactDetailForm() {
        contactDetailFormState.reset();
        editingId = null;
    }

    function handleInsertDetail() {
        const row = {
            id: ++idCounter,
            ContactDetID: null,
            ...snapshotForm()
        };

        tempDetailContact = [...tempDetailContact, row];

        resetContactDetailForm();
    }

    async function handleEditDetail(row) {
        editingId = row.id;

        untrack(() => {
            const f = contactDetailFormState.form;

            f.SiteID = row.SiteID;
            f.ContactCode = row.ContactCode;
            f.ContactEmail = row.ContactEmail;
            f.Department = row.Department;
            f.OccupationID = row.OccupationID;
            f.JobTitle = row.JobTitle;
        });
    }

    function handleUpdateDetail() {
        const updated = snapshotForm();

        tempDetailContact = tempDetailContact.map((row) =>
            row.id === editingId
                ? 
                {
                    ...row,
                    ...updated,
                    ContactDetID: row.ContactDetID ?? null
                } : row
        );

        resetContactDetailForm();
    }

    function handleCancelEditDetail() {
        resetContactDetailForm();
    }

    function handleRemoveDetail(id) {
        const row = tempDetailContact.find(r => r.id === id);
        if (row?.ContactDetID) {
            deletedDetailIds.push(row.ContactDetID);
        }
        tempDetailContact = tempDetailContact.filter((row) => row.id !== id);
        if (editingId === id) {
            resetContactDetailForm();
        }
    }

    function getLabel(fieldKey, value) {
        if (!contactDetailFormState.selectOptions?.[fieldKey]) return value;
        const option = contactDetailFormState.selectOptions[fieldKey].find(opt => opt.value === value);
        return option?.label || value || "-";
    }

    $effect(() => {
        untrack(() => {
            formFields.forEach(group => {
                group.rows.forEach(row => {
                    row.columns.forEach(col => {
                        if ((col.type === "select") && col.optionsEndpoint) {
                            formState.fetchOptions(col, formState.form);
                        }
                    });
                });
            });
        });
    });

    $effect(() => {
        untrack(() => {
            contactDetailFormFields.forEach(group => {
                group.rows.forEach(row => {
                    row.columns.forEach(col => {
                        if ((col.type === "select") && col.optionsEndpoint) {
                            contactDetailFormState.fetchOptions(col, contactDetailFormState.form);
                        }
                    });
                });
            });
        });
    });
    
    // function diffDetails(current, original) {
    //     const originalMap = new Map(
    //         original.map(item => [item.ContactDetID, item])
    //     );

    //     const updated = [];

    //     for (const item of current) {
    //         const orig = originalMap.get(item.ContactDetID);
    //         if (!orig) continue;

    //         const changed = Object.keys(item).some(
    //             key => item[key] !== orig[key]
    //         );

    //         if (changed) updated.push(item);
    //     }

    //     return updated;
    // }

    function diffDetails(currentRows, originalRows) {
        const originalMap = new Map(
            originalRows
                .filter(item => item.ContactDetID)
                .map(item => [item.ContactDetID, item])
        );

        const updated = [];
        const detailKeys = ['SiteID', 'ContactCode', 'ContactEmail', 'OccupationID', 'JobTitle', 'Department'];

        for (const item of currentRows) {
            if (!item.ContactDetID) continue;

            const orig = originalMap.get(item.ContactDetID);
            if (!orig) continue;

            const changed = detailKeys.some(
                key => item[key] !== orig[key]
            );

            if (changed) updated.push(item);
        }

        return updated;
    }

    async function handleEdit() {
        const currentPayload = buildContactPayload({
            mainForm: formState.form, 
            tempDetailContact
        });
        const originalPayload = buildContactPayload({
            mainForm: masterDetail.formSnapshot, 
            tempDetailContact: masterDetail.formSnapshot.Details ?? []
        });
        const originalRows = masterDetail.formSnapshot.Details ?? [];
        const updatedDetails = diffDetails(tempDetailContact, originalRows);

        const changedFields = getChangedFields(originalPayload, currentPayload);
        const hasMainChanges = Object.keys(changedFields).length > 0;
        const hasDetailChanges = updatedDetails.length > 0 || tempDetailContact.some(r => !r.ContactDetID) || deletedDetailIds.length > 0;
        
        if (!hasMainChanges && !hasDetailChanges) {
            toast('No changes detected');
            return;
        }

        const finalPayload = {
            ContactID: formState.form.ContactID,
            ...changedFields,
            ...(hasDetailChanges && {
                Details: {
                    created: tempDetailContact.filter(r => !r.ContactDetID),
                    edited: updatedDetails,
                    deleted: deletedDetailIds
                }
            })
        };

        console.log(finalPayload);

        const result = await formState.save(masterDetail.mode, finalPayload);
        
        if (result.status === 'success') {
            console.log('Contact updated successfully');
            toast('Contact Updated!');
            masterDetail.exitForm(true);
        } else {
            console.error('Failed to update contact:', result.message);
            const errorMessages = result.messages ? Object.values(result.messages).join('\n') : 'Failed to update contact';
            toast.error(errorMessages)
        }
    }

    const primaryAction = $derived({
        label: 'Edit',
        onClick: handleEdit,
        disabled: helpers.hasErrors || formState.isSaving.current,
        loading: formState.isSaving.current
    });

    const secondaryActions = [];

    $effect(() => {
        const mainForm = formState.form;
        if (mainForm.Details && Array.isArray(mainForm.Details)) {
            tempDetailContact = mainForm.Details.map((row, index) => ({
                id: row.id ?? index + 1,
                ...row,
            }));
        }
    })

    $effect(() => {
		const maxId = tempDetailContact.reduce((max, row) => {
			const rowId = typeof row.id === 'number' ? row.id : 0;
			return rowId > max ? rowId : max;
		}, 0);
		
		if (maxId > idCounter) {
			idCounter = maxId;
		}
	});
</script>

<FormPageContainer title="Edit Contact" {primaryAction} {secondaryActions}>
    <DictionaryFormRenderer
        {formState}
        formFields={formFields}
        mode="edit"
    />

    <Separator class="my-4"/>

    <div>
        <DictionaryFormRenderer 
            formState={contactDetailFormState}
            formFields={contactDetailFormFields}
            mode="create"
        />
        <div class="flex gap-2 mt-1 ms-2">
            {#if editingId !== null}
                <Button size="sm" class="cursor-pointer" onclick={handleUpdateDetail}>Update</Button>
                <Button size="sm" variant="outline" class="cursor-pointer" onclick={handleCancelEditDetail}>
                    Cancel
                </Button>
            {:else}
                <Button size="sm" class="cursor-pointer" onclick={handleInsertDetail}>Insert</Button>
            {/if}
        </div>
    </div>

    <div class="mt-4">
        <Separator />
        <Table.Root>
            <Table.Header>
                <Table.Row class="hover:bg-transparent">
                    <Table.Head>Site</Table.Head>
                    <Table.Head>Code</Table.Head>
                    <Table.Head>Department</Table.Head>
                    <Table.Head>Occupation</Table.Head>
                    <Table.Head>Job Title</Table.Head>
                    <Table.Head>Email</Table.Head>
                    <Table.Head class="w-[80px]"></Table.Head>
                </Table.Row>
            </Table.Header>
            <Table.Body>
                {#if tempDetailContact.length === 0}
                    <Table.Row>
                        <Table.Cell colspan={9} class="text-center text-muted-foreground py-6">
                            No data. Fill the form above and click Insert.
                        </Table.Cell>
                    </Table.Row>
                {:else}
                    {#each tempDetailContact as row (row.id)}
                        <Table.Row>
                            <Table.Cell>{row.SiteID}</Table.Cell>
                            <Table.Cell>{row.ContactCode}</Table.Cell>
                            <Table.Cell>{row.Department}</Table.Cell>
                            <Table.Cell>{row.OccupationID}</Table.Cell>
                            <Table.Cell>{row.JobTitle}</Table.Cell>
                            <Table.Cell>{row.ContactEmail}</Table.Cell>
                            <Table.Cell class="w-[80px]">
                                <div class="flex gap-1">
                                    <Button
                                        size="icon"
                                        variant="ghost"
                                        class="h-7 w-7 cursor-pointer"
                                        onclick={() => handleEditDetail(row)}
                                    >
                                        <PencilIcon class="h-3.5 w-3.5" />
                                    </Button>
                                    <Button
                                        size="icon"
                                        variant="ghost"
                                        class="h-7 w-7 cursor-pointer"
                                        onclick={() => handleRemoveDetail(row.id)}
                                    >
                                        <Trash2Icon class="h-3.5 w-3.5" />
                                    </Button>
                                </div>
                            </Table.Cell>
                        </Table.Row>
                    {/each}
                {/if}
            </Table.Body>
        </Table.Root>
    </div>
</FormPageContainer>

<ReusableAlertDialog
    bind:open={masterDetail.showExitConfirm}
    onConfirm={masterDetail.confirmExit}
/>