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

export type CuttingCatalogPrice = CuttingRawMaterialCatalogItem['prices'][number];

export function useCuttingPosCart(options: {
    rawMaterialCatalog: MaybeRefOrGetter<CuttingRawMaterialCatalogItem[]>;
    isCreateMode: MaybeRefOrGetter<boolean>;
}) {
    const materialSearch = ref('');
    const selectedRawMaterialId = ref('all');
    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[]) {
        if (!toValue(options.isCreateMode)) {
            return;
        }

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

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

        let items = catalog;
        if (rawMaterialId !== 'all') {
            const idNum = Number(rawMaterialId);
            items = catalog.filter((rawMaterial) => rawMaterial.id === idNum);
        }

        if (!keyword) {
            return items;
        }

        return items
            .map((rawMaterial) => {
                const matchingPrices = rawMaterial.prices.filter((price) =>
                    price.variant.toLowerCase().includes(keyword),
                );

                return {
                    ...rawMaterial,
                    prices: matchingPrices,
                };
            })
            .filter((rawMaterial) => rawMaterial.prices.length > 0);
    });

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

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

        upsertMaterialCartItem(item);
    }

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

        upsertMaterialCartItem(item);
    }

    async function syncDraftCombination(
        name: string | null,
        materials: Array<{ raw_material_price_id: number; material_usage: string }>,
    ) {
        const { items } = await apiFetch<{ items: CuttingMaterialCartItem[] }>(draft_combinations.store.url(), {
            method: 'POST',
            body: JSON.stringify({
                name,
                materials,
            }),
        });

        for (const item of items) {
            upsertMaterialCartItem(item);
        }

        return items;
    }

    async function removeCombination(combinationId: number) {
        try {
            await apiFetch(draft_combinations.destroy.url(combinationId), {
                method: 'DELETE',
            });

            materialCart.value = materialCart.value.filter(
                (item) => item.combination_id !== combinationId,
            );
        } catch (error) {
            toast.error(error instanceof Error ? error.message : 'Gagal menghapus kombinasi dari keranjang.');
        }
    }

    async function syncCombinationResult(combinationId: number, result: number | null) {
        materialCart.value.forEach(item => {
            if (item.combination_id === combinationId) {
                item.combination_material_result = result;
            }
        });
    }

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

    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,
            material_result: null,
            images: price.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, item.material_result);
        } catch (error) {
            toast.error(error instanceof Error ? error.message : 'Gagal memperbarui item.');
        }
    }

    return {
        materialSearch,
        selectedRawMaterialId,
        materialCart,
        resultCart,
        filteredRawMaterials,
        totalMaterialCost,
        totalResultPieces,
        estimatedCostPerUnit,
        materialLineCost,
        setCarts,
        loadDraftItems,
        getMaterialCartItem,
        addMaterial,
        removeMaterial,
        decreaseMaterialQty,
        syncMaterialField,
        syncDraftCombination,
        removeCombination,
        syncCombinationResult,
    };
}
