<script setup lang="ts">
import { Plus, Save } from '@lucide/vue';
import { computed, ref } from 'vue';
import { toast } from 'vue-sonner';
import { Button } from '@/components/ui/button';
import {
    Dialog,
    DialogContent,
    DialogHeader,
    DialogTitle,
} from '@/components/ui/dialog';
import { FieldError } from '@/components/ui/field';
import { useVariantList } from '@/composables/useVariantList';
import { apiFetch } from '@/lib/api';
import { formErrors } from '@/lib/form';
import { parseRupiah } from '@/lib/rupiah';
import RawMaterialInfoSection from '@/pages/admin/master/raw-materials/form/RawMaterialInfoSection.vue';
import RawMaterialSharedPriceSection from '@/pages/admin/master/raw-materials/form/RawMaterialSharedPriceSection.vue';
import RawMaterialVariantSection from '@/pages/admin/master/raw-materials/form/RawMaterialVariantSection.vue';
import type { CuttingRawMaterialCatalogItem } from '@/types/cutting';
import { appendMediaToFormData, createMediaUploadState } from '@/types/media';
import type { EnumOption, RawMaterialPriceFormItem } from '@/types/raw-material';

const props = defineProps<{
    units: EnumOption[];
}>();

const open = defineModel<boolean>('open', { required: true });

const emit = defineEmits<{
    'created': [rawMaterial: CuttingRawMaterialCatalogItem];
}>();

const loading = ref(false);
const selectPortalTarget = ref<HTMLElement>();

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

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

const form = ref({
    name: '',
    unit: '',
    errors: {} as Record<string, string>,
});

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

const useSamePrice = ref(true);

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 resetForm() {
    form.value = { name: '', unit: '', errors: {} };
    prices.value = [{
        client_id: createClientId(),
        variant: '',
        price: '',
        stock: '0',
        media: createMediaUploadState(),
    }];
    useSamePrice.value = true;
}

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

    formData.append('name', form.value.name.trim());
    formData.append('unit', form.value.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);
    }, 'post');

    return formData;
}

async function submit() {
    loading.value = true;
    form.value.errors = {};

    try {
        const payload = buildFormData();
        const { raw_material } = await apiFetch<{ raw_material: CuttingRawMaterialCatalogItem }>(
            '/admin/manage/cuttings/quick-create-raw-material',
            {
                method: 'POST',
                body: payload,
            },
        );

        toast.success(`Bahan baku "${raw_material.name}" berhasil ditambahkan.`);
        emit('created', raw_material);
        open.value = false;
        resetForm();
    } catch (error) {
        if (error instanceof Error) {
            toast.error(error.message);
        }
    } finally {
        loading.value = false;
    }
}
</script>

<template>
    <Dialog v-model:open="open">
        <DialogContent class="flex max-h-[90vh] flex-col sm:max-w-5xl">
            <DialogHeader>
                <DialogTitle>Tambah Bahan Baku Baru</DialogTitle>
            </DialogHeader>

            <div class="scrollbar-thin flex-1 overflow-y-auto pr-1">
                <form id="quick-create-raw-material-form" @submit.prevent="submit" class="space-y-6">
                    <RawMaterialInfoSection :form="form" :units="units" method="post"
                        :select-portal-target="selectPortalTarget" />

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

                    <RawMaterialVariantSection v-for="(price, index) in prices" :key="price.client_id" :form="form"
                        :price="price" :index="index" :total-prices="prices.length" :use-same-price="useSamePrice"
                        :price-errors="(clientId, field) => priceErrors(form, clientId, field)"
                        @remove="removePrice(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)" />

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

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

                <div class="flex gap-2">
                    <Button type="button" variant="outline" :disabled="loading" @click="open = false">
                        Batal
                    </Button>
                    <Button type="submit" form="quick-create-raw-material-form" :disabled="loading || isUploading">
                        <Save class="size-4" />
                        {{ isUploading ? 'Mengunggah...' : loading ? 'Menyimpan...' : 'Simpan' }}
                    </Button>
                </div>
            </div>

            <div ref="selectPortalTarget" class="contents"></div>
        </DialogContent>
    </Dialog>
</template>
