<script setup lang="ts">
import { useForm } from '@inertiajs/vue3';
import { Plus, Save, Search, X } from '@lucide/vue';
import { computed, ref } from 'vue';
import { toast } from 'vue-sonner';
import ConfirmDialog from '@/components/ConfirmDialog.vue';
import { Button } from '@/components/ui/button';
import { FieldError } from '@/components/ui/field';
import { Input } from '@/components/ui/input';
import { useVariantList } from '@/composables/useVariantList';
import { formErrors } from '@/lib/form';
import { parseRupiah } from '@/lib/rupiah';
import { appendMediaToFormData, createMediaUploadState } from '@/types/media';
import type {
    EnumOption,
    RawMaterialPriceFormItem,
    RawMaterialUnit,
} from '@/types/raw-material';
import RawMaterialInfoSection from './RawMaterialInfoSection.vue';
import RawMaterialSharedPriceSection from './RawMaterialSharedPriceSection.vue';
import RawMaterialVariantSection from './RawMaterialVariantSection.vue';

const props = withDefaults(
    defineProps<{
        units: EnumOption[];
        initialData?: {
            name?: string;
            unit?: RawMaterialUnit;
            prices?: Array<{
                id?: number;
                variant?: string;
                price?: string;
                stock?: string;
                images?: Array<{ id: number; url: string; thumb_url: string }>;
            }>;
        };
        submitUrl: string;
        method?: 'post' | 'put';
        submitLabel?: string;
    }>(),
    {
        method: 'post',
        submitLabel: 'Simpan',
    },
);

function createClientId(): string {
    return `price-${crypto.randomUUID()}`;
}

const isUploading = computed(() =>
    prices.value.some((p) => p.media.pendingUploads > 0)
);

const {
    items: prices,
    removeItem: removePrice,
    setField: setPriceField,
    appendToFormData,
    itemErrors: priceErrors,
} = useVariantList<RawMaterialPriceFormItem>(
    'prices',
    () => ({
        client_id: createClientId(),
        variant: '',
        price: '',
        stock: '0',
        media: createMediaUploadState(),
    }),
    () => {
        if (!props.initialData?.prices?.length) {
            return [{
                client_id: createClientId(),
                variant: '',
                price: '',
                stock: '0',
                media: createMediaUploadState(),
            }];
        }

        return props.initialData.prices.map((price) => ({
            client_id: createClientId(),
            id: price.id,
            variant: price.variant ?? '',
            price: price.price ?? '',
            stock: price.stock ?? '0',
            media: createMediaUploadState(price.images ?? []),
        }));
    },
);

const useSamePrice = ref(prices.value.length <= 1 || allPricesHaveSameValue());

const showDeleteConfirm = ref(false);
const priceToDelete = ref<string | null>(null);

async function confirmRemovePrice(clientId: string) {
    const price = prices.value.find((p) => p.client_id === clientId);

    if (price?.id) {
        try {
            const res = await fetch(`/admin/master/raw-materials/check-variant-usage?price_ids[]=${price.id}`);
            const data: { in_use: number[] } = await res.json();

            if (data.in_use?.includes(price.id)) {
                toast.error(`Varian "${price.variant}" tidak dapat dihapus karena masih digunakan dalam proses cutting yang belum selesai.`);
                return;
            }
        } catch {
            // proceed to confirm dialog if check fails
        }
    }

    priceToDelete.value = clientId;
    showDeleteConfirm.value = true;
}

function handleRemovePrice() {
    if (priceToDelete.value) {
        removePrice(priceToDelete.value);
        priceToDelete.value = null;
    }
    showDeleteConfirm.value = false;
}

const form = useForm({
    name: props.initialData?.name ?? '',
    unit: props.initialData?.unit ?? '',
});

function allPricesHaveSameValue(): boolean {
    if (prices.value.length <= 1) {
        return true;
    }

    const first = prices.value[0].price.trim();

    return prices.value.every((item) => item.price.trim() === first);
}

const variantSearchQuery = ref('');

function shouldShowVariant(price: RawMaterialPriceFormItem, index: number) {
    const hasError = Object.keys(form.errors).some((key) => key.startsWith(`prices.${index}.`));
    if (hasError) {
        return true;
    }

    const query = variantSearchQuery.value.trim().toLowerCase();
    if (!query) {
        return true;
    }

    return price.variant.toLowerCase().includes(query) || price.variant.trim() === '';
}

const hasVisiblePrices = computed(() => {
    return prices.value.some((price, index) => shouldShowVariant(price, index));
});

function handleAddPrice() {
    variantSearchQuery.value = '';
    addPrice();
}

function addPrice() {
    const newPrice: RawMaterialPriceFormItem = {
        client_id: createClientId(),
        variant: '',
        price: '',
        stock: '0',
        media: createMediaUploadState(),
    };

    if (useSamePrice.value && prices.value[0]) {
        newPrice.price = prices.value[0].price;
    }

    prices.value = [...prices.value, newPrice];
}

function setPriceValue(clientId: string, value: string) {
    setPriceField(clientId, 'price', value);
}

function setSharedPrice(value: string) {
    prices.value = prices.value.map((price) => ({ ...price, price: value }));
}

function toggleUseSamePrice(checked: boolean) {
    useSamePrice.value = checked;

    if (!checked || !prices.value[0]) {
        return;
    }

    const sourcePrice = prices.value[0].price;
    prices.value = prices.value.map((price) => ({ ...price, price: sourcePrice }));
}

function applyPriceToAllVariants(sourceClientId: string) {
    const source = prices.value.find((price) => price.client_id === sourceClientId);

    if (!source) {
        return;
    }

    prices.value = prices.value.map((price) => ({ ...price, price: source.price }));
}

function parseStockValue(value: string): number {
    const parsed = Number.parseFloat(value.replace(',', '.'));

    return Number.isNaN(parsed) ? 0 : parsed;
}

function buildFormData(): FormData {
    const formData = new FormData();

    formData.append('name', form.name.trim());
    formData.append('unit', form.unit);

    appendToFormData(formData, (formData, index, price) => {
        formData.append(`prices[${index}][variant]`, price.variant.trim());
        formData.append(`prices[${index}][price]`, String(Number.parseInt(parseRupiah(price.price), 10) || 0));
        formData.append(`prices[${index}][stock]`, String(parseStockValue(price.stock)));
        appendMediaToFormData(formData, `prices[${index}]`, price.media);
    }, props.method);

    return formData;
}

function submit() {
    const payload = buildFormData();

    form.transform(() => payload).post(props.submitUrl, {
        forceFormData: true,
        onError: (errors: Record<string, string>) => {
            if (errors.system) {
                toast.error(errors.system);
            }
            if (errors.prices) {
                toast.error(errors.prices);
            }
        },
    });
}
</script>

<template>
    <form @submit.prevent="submit">
        <div class="grid gap-6">
            <RawMaterialInfoSection :form="form" :units="units" :method="method" />

            <RawMaterialSharedPriceSection :form="form" :prices="prices" :use-same-price="useSamePrice"
                @toggle-use-same-price="toggleUseSamePrice" @set-shared-price="setSharedPrice" />

            <!-- Section pencarian varian -->
            <div v-if="prices.length > 0" class="flex flex-col gap-2 md:flex-row md:items-center md:justify-between">
                <h3 class="text-lg font-semibold tracking-tight">Daftar Varian ({{ prices.length }})</h3>
                <div v-if="prices.length > 1" class="relative w-full md:max-w-xs">
                    <Search class="absolute left-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground" />
                    <Input
                        v-model="variantSearchQuery"
                        type="text"
                        placeholder="Cari varian berdasarkan nama..."
                        class="pl-9 pr-8 h-9 w-full bg-background"
                    />
                    <button
                        v-if="variantSearchQuery"
                        type="button"
                        class="absolute right-2.5 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground transition-colors p-0.5 rounded-full hover:bg-muted cursor-pointer flex items-center justify-center"
                        @click="variantSearchQuery = ''"
                    >
                        <X class="size-3.5" />
                    </button>
                </div>
            </div>

            <RawMaterialVariantSection v-for="(price, index) in prices" :key="price.client_id"
                v-show="shouldShowVariant(price, index)"
                :form="form"
                :price="price" :index="index" :total-prices="prices.length" :use-same-price="useSamePrice"
                :price-errors="(clientId, field) => priceErrors(form, clientId, field)"
                @remove="confirmRemovePrice(price.client_id)" @apply-price-to-all="applyPriceToAllVariants(price.client_id)"
                @update:variant="setPriceField(price.client_id, 'variant', $event)"
                @update:stock="setPriceField(price.client_id, 'stock', $event)"
                @update:price="setPriceValue(price.client_id, $event)" />

            <div v-if="prices.length > 0 && !hasVisiblePrices" class="flex flex-col items-center justify-center p-8 border border-dashed rounded-lg bg-muted/40 text-center animate-in fade-in duration-200">
                <Search class="size-8 text-muted-foreground mb-2" />
                <p class="text-sm font-medium">Tidak ada varian yang cocok</p>
                <p class="text-xs text-muted-foreground mt-0.5">Tidak ditemukan varian dengan nama "{{ variantSearchQuery }}"</p>
                <Button type="button" variant="outline" size="sm" class="mt-4 cursor-pointer" @click="variantSearchQuery = ''">
                    Clear Pencarian
                </Button>
            </div>

            <FieldError :errors="formErrors(form, 'prices')" />

            <div class="flex items-center justify-between gap-2">
                <Button type="button" variant="outline" @click="handleAddPrice">
                    <Plus class="size-4" />
                    Tambah Varian
                </Button>

                <Button type="submit" :disabled="form.processing || isUploading">
                    <Save class="size-4" />
                    {{ isUploading ? 'Mengunggah...' : form.processing ? 'Menyimpan...' : submitLabel }}
                </Button>
            </div>
        </div>
    </form>

    <ConfirmDialog
        v-model:open="showDeleteConfirm"
        title="Hapus Varian?"
        description="Apakah Anda yakin ingin menghapus varian ini? Tindakan ini tidak dapat dibatalkan."
        confirm-label="Hapus"
        cancel-label="Batal"
        destructive
        @confirm="handleRemovePrice"
    />
</template>
