import { computed, ref, watch, type MaybeRefOrGetter, toValue } from 'vue';
import { toast } from 'vue-sonner';
import { OrderChannel } from '@/constants/order-channel';
import { StockQuality } from '@/constants/stock-quality';
import { apiFetch } from '@/lib/api';
import { store as syncDraftRoute, resync_prices as resyncPricesRoute, destroy as destroyDraftRoute } from '@/routes/admin/manage/orders/draft_items';
import { STOCK_QUALITY_OPTIONS } from '@/types/order';
import type { OrderCartItem, OrderCatalogItem } from '@/types/order';
import type { ProductPriceItem, ProductVariantItem } from '@/types/product';

export function useOrderPosCart(options: {
    catalog: MaybeRefOrGetter<OrderCatalogItem[]>;
    isCreateMode: MaybeRefOrGetter<boolean>;
    priceType: MaybeRefOrGetter<string>;
    isCashierUser: MaybeRefOrGetter<boolean>;
}) {
    const search = ref('');
    const selectedStockQuality = ref<'good' | 'reject' | 'retail'>(
        toValue(options.isCashierUser) ? StockQuality.RETAIL : StockQuality.GOOD,
    );
    const cart = ref<OrderCartItem[]>([]);

    function setCart(items: OrderCartItem[]) {
        cart.value = items.map((item) => ({
            ...item,
            stock_quality: item.stock_quality ?? StockQuality.GOOD,
        }));
    }

    function loadDraftItems(items: OrderCartItem[]) {
        if (!toValue(options.isCreateMode) || items.length === 0) {
            return;
        }

        cart.value = items.map((item) => ({ ...item }));
    }

    watch(
        () => toValue(options.priceType),
        async (priceType) => {
            if (!toValue(options.isCreateMode) || cart.value.length === 0) {
                return;
            }

            try {
                const { items } = await apiFetch<{ items: OrderCartItem[] }>(
                    resyncPricesRoute.url(),
                    {
                        method: 'PUT',
                        body: JSON.stringify({ price_type: priceType }),
                    },
                );

                cart.value = items.map((item) => ({ ...item }));
            } catch (error) {
                toast.error(error instanceof Error ? error.message : 'Gagal memperbarui harga keranjang.');
            }
        },
    );

    function upsertCartItem(item: OrderCartItem) {
        const index = cart.value.findIndex(
            (cartItem) =>
                cartItem.product_variant_id === item.product_variant_id
                && cartItem.stock_quality === item.stock_quality,
        );

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

            return;
        }

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

    function availableStockForVariant(variant: ProductVariantItem, stockQuality: string): number {
        if (stockQuality === StockQuality.REJECT) {
            return variant.reject_stock;
        }

        if (stockQuality === StockQuality.RETAIL) {
            return variant.retail_stock ?? 0;
        }

        return variant.stock;
    }

    const filteredCatalog = computed(() => {
        const keyword = search.value.trim().toLowerCase();
        const catalog = toValue(options.catalog);

        if (!keyword) {
            return catalog;
        }

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

    const subtotal = computed(() =>
        cart.value.reduce((sum, item) => sum + lineSubtotal(item), 0),
    );

    function getVariantPrice(variant: ProductVariantItem): ProductPriceItem | undefined {
        return variant.prices.find((price) => price.type === toValue(options.priceType));
    }

    function getCartItem(variantId: number, stockQuality = selectedStockQuality.value): OrderCartItem | undefined {
        return cart.value.find(
            (item) =>
                item.product_variant_id === variantId
                && item.stock_quality === stockQuality,
        );
    }

    function stockQualityLabel(stockQuality: string): string {
        if (stockQuality === StockQuality.REJECT) {
            return 'Reject';
        }

        if (stockQuality === StockQuality.RETAIL) {
            return 'Eceran';
        }

        return 'Bagus';
    }

    function lineSubtotal(item: OrderCartItem): number {
        const quantity = Number(item.quantity) || 0;

        return quantity * item.unit_price;
    }

    async function syncDraftItem(variantId: number, quantity: number, stockQuality: string = selectedStockQuality.value) {
        const { item } = await apiFetch<{ item: OrderCartItem }>(syncDraftRoute.url(), {
            method: 'POST',
            body: JSON.stringify({
                product_variant_id: variantId,
                quantity,
                price_type: toValue(options.priceType),
                stock_quality: stockQuality,
            }),
        });

        upsertCartItem(item);
    }

    async function addToCart(product: OrderCatalogItem, variant: ProductVariantItem) {
        const price = getVariantPrice(variant);

        if (!price) {
            toast.error('Harga untuk tipe harga ini belum diatur.');

            return;
        }

        const stockQuality = selectedStockQuality.value;
        const availableStock = availableStockForVariant(variant, stockQuality);

        if (availableStock < 1) {
            toast.error(`Stok ${stockQualityLabel(stockQuality)} tidak tersedia.`);

            return;
        }

        const existing = cart.value.find(
            (item) =>
                item.product_variant_id === variant.id
                && item.stock_quality === stockQuality,
        );
        const nextQty = existing ? (Number(existing.quantity) || 0) + 1 : 1;

        if (nextQty > availableStock) {
            toast.error(`Stok ${stockQualityLabel(stockQuality)} tidak mencukupi.`);

            return;
        }

        if (toValue(options.isCreateMode)) {
            try {
                await syncDraftItem(variant.id, nextQty, stockQuality);
            } catch (error) {
                toast.error(error instanceof Error ? error.message : 'Gagal menyimpan item ke keranjang.');
            }

            return;
        }

        if (existing) {
            existing.quantity = String(nextQty);

            return;
        }

        cart.value.push({
            product_variant_id: variant.id,
            product_name: product.name,
            variant_name: variant.name,
            stock_quality: stockQuality,
            stock_quality_label: STOCK_QUALITY_OPTIONS.find((option) => option.value === stockQuality)?.label,
            quantity: '1',
            unit_price: Number(price.price_input ?? price.price),
            images: variant.images ?? [],
        });
    }

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

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

                return;
            }
        }

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

    async function adjustQuantity(index: number, delta: number) {
        const item = cart.value[index];
        const nextQty = (Number(item.quantity) || 0) + delta;

        if (nextQty < 1) {
            await removeFromCart(index);

            return;
        }

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

            return;
        }

        item.quantity = String(nextQty);
    }

    async function syncCartItemQuantity(index: number) {
        const item = cart.value[index];
        const nextQty = Number(item.quantity) || 0;

        if (nextQty < 1) {
            await removeFromCart(index);

            return;
        }

        if (!toValue(options.isCreateMode)) {
            return;
        }

        try {
            await syncDraftItem(item.product_variant_id, nextQty, item.stock_quality);
        } catch (error) {
            toast.error(error instanceof Error ? error.message : 'Gagal memperbarui jumlah item.');
        }
    }

    async function decreaseVariantQty(variantId: number) {
        const index = cart.value.findIndex(
            (item) =>
                item.product_variant_id === variantId
                && item.stock_quality === selectedStockQuality.value,
        );

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

    return {
        search,
        selectedStockQuality,
        cart,
        filteredCatalog,
        subtotal,
        setCart,
        loadDraftItems,
        getVariantPrice,
        getCartItem,
        lineSubtotal,
        stockQualityLabel,
        addToCart,
        removeFromCart,
        adjustQuantity,
        syncCartItemQuantity,
        decreaseVariantQty,
    };
}
