import { useDebounceFn } from '@vueuse/core';
import { computed, ref, watch, type MaybeRefOrGetter, toValue } from 'vue';
import { apiFetch } from '@/lib/api';
import { auto_save } from '@/routes/admin/manage/stok-opnames';
import type {
    CatalogProduct,
    StokOpnameExistingItem,
    StokOpnameProductGroup,
    StokOpnameVariantRow,
} from '@/types/stok-opname';

export function buildStokOpnameVariantRows(
    catalog: CatalogProduct[],
    existingItems: StokOpnameExistingItem[] = [],
): StokOpnameVariantRow[] {
    const existingMap = new Map<number, { physical_stock: number; notes: string }>();

    for (const item of existingItems) {
        existingMap.set(item.product_variant_id, {
            physical_stock: item.physical_stock,
            notes: item.notes ?? '',
        });
    }

    const rows: StokOpnameVariantRow[] = [];

    for (const product of catalog) {
        for (const variant of product.variants) {
            const existing = existingMap.get(variant.id);

            rows.push({
                product_name: product.name,
                variant_id: variant.id,
                variant_name: variant.name,
                system_stock: variant.stock,
                system_stock_formatted: variant.stock_formatted,
                physical_stock: existing?.physical_stock ?? 0,
                notes: existing?.notes ?? '',
            });
        }
    }

    return rows;
}

export function useStokOpnameForm(options: {
    catalog: MaybeRefOrGetter<CatalogProduct[]>;
    initialOpnameDate: MaybeRefOrGetter<string>;
    initialNotes: MaybeRefOrGetter<string>;
    initialStokOpnameId: MaybeRefOrGetter<number | null>;
    existingItems?: MaybeRefOrGetter<StokOpnameExistingItem[]>;
}) {
    const opnameDate = ref(toValue(options.initialOpnameDate));
    const notes = ref(toValue(options.initialNotes));
    const stokOpnameId = ref<number | null>(toValue(options.initialStokOpnameId));
    const saving = ref(false);
    const lastSaved = ref<string | null>(null);

    const variantRows = ref<StokOpnameVariantRow[]>(
        buildStokOpnameVariantRows(
            toValue(options.catalog),
            toValue(options.existingItems) ?? [],
        ),
    );

    const itemsPayload = computed(() =>
        variantRows.value
            .filter((row) => row.physical_stock > 0 || row.notes.trim() !== '')
            .map((row) => ({
                product_variant_id: row.variant_id,
                physical_stock: row.physical_stock,
                notes: row.notes || null,
            })),
    );

    const groupedProducts = computed<StokOpnameProductGroup[]>(() => {
        const groups: StokOpnameProductGroup[] = [];
        let currentProduct = '';
        let currentGroup: StokOpnameProductGroup | null = null;
        let idx = 0;

        for (const row of variantRows.value) {
            if (row.product_name !== currentProduct) {
                currentProduct = row.product_name;
                currentGroup = { product_name: row.product_name, rows: [], startIndex: idx };
                groups.push(currentGroup);
            }

            currentGroup!.rows.push(row);
            idx++;
        }

        return groups;
    });

    const autoSave = useDebounceFn(async () => {
        if (variantRows.value.length === 0) {
            return;
        }

        saving.value = true;

        try {
            const data = await apiFetch<{ stok_opname_id: number }>(auto_save.url(), {
                method: 'POST',
                body: JSON.stringify({
                    stok_opname_id: stokOpnameId.value,
                    opname_date: opnameDate.value,
                    notes: notes.value || null,
                    items: itemsPayload.value,
                }),
            });

            stokOpnameId.value = data.stok_opname_id;
            lastSaved.value = new Date().toLocaleTimeString('id-ID');
        } catch {
            // Auto-save is silent; user can retry on next change.
        } finally {
            saving.value = false;
        }
    }, 1000);

    watch([opnameDate, notes], () => autoSave());

    function onRowChange() {
        autoSave();
    }

    return {
        opnameDate,
        notes,
        stokOpnameId,
        saving,
        lastSaved,
        variantRows,
        itemsPayload,
        groupedProducts,
        onRowChange,
    };
}
