import { useDebounceFn } from '@vueuse/core';
import { computed, ref, watch,  toValue } from 'vue';
import type {MaybeRefOrGetter} 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<string, { physical_stock: number; notes: string }>();

    for (const item of existingItems) {
        const key = `${item.product_variant_id}_${item.stock_quality}`;
        existingMap.set(key, {
            physical_stock: item.physical_stock,
            notes: item.notes ?? '',
        });
    }

    const rows: StokOpnameVariantRow[] = [];
    const qualities = [
        { key: 'good', label: 'Bagus' },
        { key: 'retail', label: 'Eceran' },
        { key: 'reject', label: 'Reject' },
    ] as const;

    for (const product of catalog) {
        for (const variant of product.variants) {
            for (const quality of qualities) {
                const key = `${variant.id}_${quality.key}`;
                const existing = existingMap.get(key);

                let systemStock = 0;
                let systemStockFormatted = '0';
                if (quality.key === 'good') {
                    systemStock = variant.stock;
                    systemStockFormatted = variant.stock_formatted ?? '0';
                } else if (quality.key === 'retail') {
                    systemStock = variant.retail_stock ?? 0;
                    systemStockFormatted = variant.retail_stock_formatted ?? '0';
                } else if (quality.key === 'reject') {
                    systemStock = variant.reject_stock ?? 0;
                    systemStockFormatted = variant.reject_stock_formatted ?? '0';
                }

                rows.push({
                    product_name: product.name,
                    variant_id: variant.id,
                    variant_name: `${variant.name} (${quality.label})`,
                    variant_name_raw: variant.name,
                    stock_quality: quality.key,
                    system_stock: systemStock,
                    system_stock_formatted: systemStockFormatted,
                    physical_stock: existing?.physical_stock ?? systemStock,
                    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 !== row.system_stock || row.notes.trim() !== '')
            .map((row) => ({
                product_variant_id: row.variant_id,
                stock_quality: row.stock_quality,
                physical_stock: row.physical_stock,
                notes: row.notes || null,
            })),
    );

    const groupedProducts = computed<StokOpnameProductGroup[]>(() => {
        const groups: StokOpnameProductGroup[] = [];
        const productMap = new Map<string, Map<number, { variant_name: string; rows: StokOpnameVariantRow[] }>>();

        for (const row of variantRows.value) {
            if (!productMap.has(row.product_name)) {
                productMap.set(row.product_name, new Map());
            }
            const variantMap = productMap.get(row.product_name)!;
            if (!variantMap.has(row.variant_id)) {
                variantMap.set(row.variant_id, { variant_name: row.variant_name_raw || row.variant_name, rows: [] });
            }
            variantMap.get(row.variant_id)!.rows.push(row);
        }

        let variantIndex = 0;
        for (const [productName, variantMap] of productMap.entries()) {
            const productGroup: StokOpnameProductGroup = {
                product_name: productName,
                variants: [],
                startIndex: variantIndex,
            };

            for (const [variantId, vData] of variantMap.entries()) {
                productGroup.variants.push({
                    variant_id: variantId,
                    variant_name: vData.variant_name,
                    qualities: vData.rows.map((row) => {
                        const qualityLabel = row.stock_quality === 'good' ? 'Bagus' : (row.stock_quality === 'retail' ? 'Eceran' : 'Reject');
                        return {
                            quality_key: row.stock_quality,
                            quality_label: qualityLabel,
                            system_stock: row.system_stock,
                            system_stock_formatted: row.system_stock_formatted,
                            row_ref: row,
                        };
                    }),
                });
                variantIndex++;
            }

            groups.push(productGroup);
        }

        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,
    };
}
