import { computed, ref, type MaybeRefOrGetter, toValue } from 'vue';
import { toast } from 'vue-sonner';
import { apiFetch } from '@/lib/api';
import draft_materials from '@/routes/admin/manage/cuttings/draft_materials';
import draft_results from '@/routes/admin/manage/cuttings/draft_results';
import type {
    CuttingMaterialCartItem,
    CuttingProductCatalogItem,
    CuttingRawMaterialCatalogItem,
    CuttingResultCartItem,
} from '@/types/cutting';

export type CuttingCatalogPrice = CuttingRawMaterialCatalogItem['prices'][number];
export type CuttingCatalogVariant = CuttingProductCatalogItem['variants'][number];

export function useCuttingPosCart(options: {
    rawMaterialCatalog: MaybeRefOrGetter<CuttingRawMaterialCatalogItem[]>;
    productCatalog: MaybeRefOrGetter<CuttingProductCatalogItem[]>;
    isCreateMode: MaybeRefOrGetter<boolean>;
}) {
    const materialSearch = ref('');
    const productSearch = ref('');
    const materialCart = ref<CuttingMaterialCartItem[]>([]);
    const resultCart = ref<CuttingResultCartItem[]>([]);

    function findCatalogPrice(priceId: number) {
        for (const rawMaterial of toValue(options.rawMaterialCatalog)) {
            const price = rawMaterial.prices.find((item) => item.id === priceId);

            if (price) {
                return {
                    price: price.price,
                    unit: rawMaterial.unit,
                };
            }
        }

        return null;
    }

    function setCarts(materials: CuttingMaterialCartItem[], results: CuttingResultCartItem[]) {
        materialCart.value = materials.map((item) => ({ ...item }));
        resultCart.value = results.map((item) => ({ ...item }));
    }

    function loadDraftItems(materials: CuttingMaterialCartItem[], results: CuttingResultCartItem[]) {
        if (!toValue(options.isCreateMode)) {
            return;
        }

        if (materials.length > 0) {
            materialCart.value = materials.map((item) => ({ ...item }));
        }

        if (results.length > 0) {
            resultCart.value = results.map((item) => ({ ...item }));
        }
    }

    const filteredRawMaterials = computed(() => {
        const keyword = materialSearch.value.trim().toLowerCase();
        const catalog = toValue(options.rawMaterialCatalog);

        if (!keyword) {
            return catalog;
        }

        return catalog.filter(
            (rawMaterial) =>
                rawMaterial.name.toLowerCase().includes(keyword)
                || rawMaterial.prices.some((price) => price.variant.toLowerCase().includes(keyword)),
        );
    });

    const filteredProducts = computed(() => {
        const keyword = productSearch.value.trim().toLowerCase();
        const catalog = toValue(options.productCatalog);

        if (!keyword) {
            return catalog;
        }

        return catalog.filter(
            (product) =>
                product.name.toLowerCase().includes(keyword)
                || product.variants.some((variant) => variant.name.toLowerCase().includes(keyword)),
        );
    });

    const totalMaterialCost = computed(() =>
        materialCart.value.reduce((sum, item) => sum + materialLineCost(item), 0),
    );

    const totalResultPieces = computed(() =>
        resultCart.value.reduce(
            (sum, item) => sum + (Number(item.cutting_result) || 0),
            0,
        ),
    );

    const estimatedCostPerUnit = computed(() => {
        if (totalResultPieces.value <= 0) {
            return 0;
        }

        return Math.round(totalMaterialCost.value / totalResultPieces.value);
    });

    function materialLineCost(item: CuttingMaterialCartItem): number {
        const catalogPrice = findCatalogPrice(item.raw_material_price_id);

        if (!catalogPrice) {
            return 0;
        }

        const usage = Number(item.material_usage) || 0;

        return Math.round(usage * catalogPrice.price);
    }

    function upsertMaterialCartItem(item: CuttingMaterialCartItem) {
        const index = materialCart.value.findIndex(
            (cartItem) => cartItem.raw_material_price_id === item.raw_material_price_id,
        );

        if (index === -1) {
            materialCart.value.push({ ...item });

            return;
        }

        materialCart.value[index] = { ...item };
    }

    function upsertResultCartItem(item: CuttingResultCartItem) {
        const index = resultCart.value.findIndex(
            (cartItem) => cartItem.product_variant_id === item.product_variant_id,
        );

        if (index === -1) {
            resultCart.value.push({ ...item });

            return;
        }

        resultCart.value[index] = { ...item };
    }

    async function syncDraftMaterial(
        rawMaterial: CuttingRawMaterialCatalogItem,
        price: CuttingCatalogPrice,
        materialUsage: string,
    ) {
        const { item } = await apiFetch<{ item: CuttingMaterialCartItem }>(draft_materials.store.url(), {
            method: 'POST',
            body: JSON.stringify({
                raw_material_price_id: price.id,
                material_usage: materialUsage,
            }),
        });

        upsertMaterialCartItem(item);
    }

    async function syncDraftMaterialById(priceId: number, materialUsage: string) {
        const { item } = await apiFetch<{ item: CuttingMaterialCartItem }>(draft_materials.store.url(), {
            method: 'POST',
            body: JSON.stringify({
                raw_material_price_id: priceId,
                material_usage: materialUsage,
            }),
        });

        upsertMaterialCartItem(item);
    }

    async function syncDraftResult(
        product: CuttingProductCatalogItem,
        variant: CuttingCatalogVariant,
        cuttingResult: string,
        sample: string,
        originalOutsideSample: string,
    ) {
        const { item } = await apiFetch<{ item: CuttingResultCartItem }>(draft_results.store.url(), {
            method: 'POST',
            body: JSON.stringify({
                product_variant_id: variant.id,
                cutting_result: cuttingResult,
                sample,
                original_outside_sample: originalOutsideSample,
            }),
        });

        upsertResultCartItem(item);
    }

    async function syncDraftResultById(
        variantId: number,
        cuttingResult: string,
        sample: string,
        originalOutsideSample: string,
    ) {
        const { item } = await apiFetch<{ item: CuttingResultCartItem }>(draft_results.store.url(), {
            method: 'POST',
            body: JSON.stringify({
                product_variant_id: variantId,
                cutting_result: cuttingResult,
                sample,
                original_outside_sample: originalOutsideSample,
            }),
        });

        upsertResultCartItem(item);
    }

    function getMaterialCartItem(priceId: number): CuttingMaterialCartItem | undefined {
        return materialCart.value.find((item) => item.raw_material_price_id === priceId);
    }

    function getResultCartItem(variantId: number): CuttingResultCartItem | undefined {
        return resultCart.value.find((item) => item.product_variant_id === variantId);
    }

    function syncResultTotals(item: CuttingResultCartItem) {
        const total = Number(item.cutting_result) || 0;
        const sample = Number(item.sample) || 0;

        item.original_outside_sample = String(Math.max(total - sample, 0));
    }

    async function removeMaterial(index: number) {
        const item = materialCart.value[index];

        if (toValue(options.isCreateMode)) {
            try {
                await apiFetch(draft_materials.destroy.url(item.raw_material_price_id), {
                    method: 'DELETE',
                });
            } catch (error) {
                toast.error(error instanceof Error ? error.message : 'Gagal menghapus item dari keranjang.');

                return;
            }
        }

        materialCart.value.splice(index, 1);
    }

    async function decreaseMaterialQty(priceId: number) {
        const item = materialCart.value.find((i) => i.raw_material_price_id === priceId);

        if (!item) {
            return;
        }

        const nextQty = (Number(item.material_usage) || 0) - 1;

        if (nextQty <= 0) {
            const index = materialCart.value.findIndex((i) => i.raw_material_price_id === priceId);

            if (index !== -1) {
                await removeMaterial(index);
            }

            return;
        }

        if (toValue(options.isCreateMode)) {
            try {
                await syncDraftMaterialById(priceId, String(nextQty));
            } catch (error) {
                toast.error(error instanceof Error ? error.message : 'Gagal memperbarui jumlah item.');
            }

            return;
        }

        item.material_usage = String(nextQty);
    }

    async function addMaterial(rawMaterial: CuttingRawMaterialCatalogItem, price: CuttingCatalogPrice) {
        const existing = materialCart.value.find(
            (item) => item.raw_material_price_id === price.id,
        );
        const defaultUsage = '1';
        const nextUsage = existing
            ? String((Number(existing.material_usage) || 0) + 1)
            : defaultUsage;

        if (toValue(options.isCreateMode)) {
            try {
                await syncDraftMaterial(rawMaterial, price, nextUsage);
            } catch (error) {
                toast.error(error instanceof Error ? error.message : 'Gagal menyimpan item ke keranjang.');
            }

            return;
        }

        if (existing) {
            existing.material_usage = nextUsage;

            return;
        }

        materialCart.value.push({
            raw_material_price_id: price.id,
            raw_material_name: rawMaterial.name,
            variant: price.variant,
            unit: rawMaterial.unit,
            unit_abbreviation: rawMaterial.unit_abbreviation,
            stock_input: price.stock_input,
            material_usage: defaultUsage,
            images: price.images ?? [],
        });
    }

    async function removeResult(index: number) {
        const item = resultCart.value[index];

        if (toValue(options.isCreateMode)) {
            try {
                await apiFetch(draft_results.destroy.url(item.product_variant_id), {
                    method: 'DELETE',
                });
            } catch (error) {
                toast.error(error instanceof Error ? error.message : 'Gagal menghapus item dari keranjang.');

                return;
            }
        }

        resultCart.value.splice(index, 1);
    }

    async function decreaseResultQty(variantId: number) {
        const item = resultCart.value.find((i) => i.product_variant_id === variantId);

        if (!item) {
            return;
        }

        const nextQty = (Number(item.cutting_result) || 0) - 1;

        if (nextQty <= 0) {
            const index = resultCart.value.findIndex((i) => i.product_variant_id === variantId);

            if (index !== -1) {
                await removeResult(index);
            }

            return;
        }

        const nextsample = Math.max(0, (Number(item.sample) || 0) - 1);
        const nextoriginalOutsideSample = Math.max(nextQty - nextsample, 0);

        if (toValue(options.isCreateMode)) {
            try {
                await syncDraftResultById(
                    variantId,
                    String(nextQty),
                    String(nextsample),
                    String(nextoriginalOutsideSample),
                );
            } catch (error) {
                toast.error(error instanceof Error ? error.message : 'Gagal memperbarui jumlah item.');
            }

            return;
        }

        item.cutting_result = String(nextQty);
        item.sample = String(nextsample);
        syncResultTotals(item);
    }

    async function addResult(product: CuttingProductCatalogItem, variant: CuttingCatalogVariant) {
        const existing = resultCart.value.find(
            (item) => item.product_variant_id === variant.id,
        );
        const nextQty = existing ? (Number(existing.cutting_result) || 0) + 1 : 1;
        const nextsample = existing ? (Number(existing.sample) || 0) + 1 : 1;
        const nextoriginalOutsideSample = Math.max(nextQty - nextsample, 0);

        if (toValue(options.isCreateMode)) {
            try {
                await syncDraftResult(
                    product,
                    variant,
                    String(nextQty),
                    String(nextsample),
                    String(nextoriginalOutsideSample),
                );
            } catch (error) {
                toast.error(error instanceof Error ? error.message : 'Gagal menyimpan item ke keranjang.');
            }

            return;
        }

        if (existing) {
            existing.cutting_result = String(nextQty);
            existing.sample = String(nextsample);
            syncResultTotals(existing);

            return;
        }

        resultCart.value.push({
            product_variant_id: variant.id,
            product_name: product.name,
            variant_name: variant.name,
            stock: variant.stock,
            cutting_result: '1',
            sample: '1',
            original_outside_sample: '0',
            images: variant.images ?? [],
        });
    }

    async function syncMaterialField(index: number) {
        if (!toValue(options.isCreateMode)) {
            return;
        }

        const item = materialCart.value[index];

        try {
            await syncDraftMaterialById(item.raw_material_price_id, item.material_usage);
        } catch (error) {
            toast.error(error instanceof Error ? error.message : 'Gagal memperbarui item.');
        }
    }

    async function syncResultField(index: number) {
        if (!toValue(options.isCreateMode)) {
            return;
        }

        const item = resultCart.value[index];

        try {
            await syncDraftResultById(
                item.product_variant_id,
                item.cutting_result,
                item.sample,
                item.original_outside_sample,
            );
        } catch (error) {
            toast.error(error instanceof Error ? error.message : 'Gagal memperbarui item.');
        }
    }

    return {
        materialSearch,
        productSearch,
        materialCart,
        resultCart,
        filteredRawMaterials,
        filteredProducts,
        totalMaterialCost,
        totalResultPieces,
        estimatedCostPerUnit,
        materialLineCost,
        setCarts,
        loadDraftItems,
        getMaterialCartItem,
        getResultCartItem,
        syncResultTotals,
        addMaterial,
        removeMaterial,
        decreaseMaterialQty,
        addResult,
        removeResult,
        decreaseResultQty,
        syncMaterialField,
        syncResultField,
    };
}
