<script setup lang="ts">
import { useForm } from '@inertiajs/vue3';
import { Plus, Save } from '@lucide/vue';
import { computed } from 'vue';
import { toast } from 'vue-sonner';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { useVariantList } from '@/composables/useVariantList';
import { appendMediaToFormData, createMediaUploadState } from '@/types/media';
import type { CategoryOption, ProductFormInitialData, ProductVariantFormItem } from '@/types/product';
import ProductInfoSection from './ProductInfoSection.vue';
import ProductVariantSection from './ProductVariantSection.vue';

const props = withDefaults(
    defineProps<{
        categories: CategoryOption[];
        initialData?: ProductFormInitialData;
        submitUrl: string;
        method?: 'post' | 'put';
        submitLabel?: string;
    }>(),
    {
        method: 'post',
        submitLabel: 'Simpan',
    },
);

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

const {
    items: variants,
    addItem: addVariant,
    removeItem: removeVariant,
    setField: setVariantField,
    appendToFormData,
    itemErrors: variantErrors,
} = useVariantList<ProductVariantFormItem>(
    'variants',
    () => ({
        client_id: createClientId(),
        name: '',
        stock: '0',
        retail_stock: '0',
        media: createMediaUploadState(),
    }),
    () => {
        if (!props.initialData?.variants?.length) {
            return [{
                client_id: createClientId(),
                name: '',
                stock: '0',
                retail_stock: '0',
                media: createMediaUploadState(),
            }];
        }

        return props.initialData.variants.map((variant) => ({
            client_id: createClientId(),
            id: variant.id,
            name: variant.name ?? '',
            stock: variant.stock != null ? String(variant.stock) : '0',
            retail_stock: variant.retail_stock != null ? String(variant.retail_stock) : '0',
            media: createMediaUploadState(variant.images ?? []),
        }));
    },
);

const form = useForm({
    name: props.initialData?.name ?? '',
    description: props.initialData?.description ?? '',
    category_ids: props.initialData?.category_ids ?? [],
});

const categoryError = computed(() => form.errors.category_ids);

function toggleCategory(categoryId: number, checked: boolean) {
    if (checked) {
        if (!form.category_ids.includes(categoryId)) {
            form.category_ids = [...form.category_ids, categoryId];
        }

        return;
    }

    form.category_ids = form.category_ids.filter((id) => id !== categoryId);
}

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

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

    form.category_ids.forEach((categoryId) => {
        formData.append('category_ids[]', String(categoryId));
    });

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

    return formData;
}

function submit() {
    const options = {
        forceFormData: true,
        onError: (errors: Record<string, string>) => {
            if (errors.system) {
                toast.error(errors.system);
            }
        },
    };

    const payload = buildFormData();

    form.transform(() => payload).post(props.submitUrl, options);
}
</script>

<template>
    <form @submit.prevent="submit">
        <div class="grid gap-6">
            <Card>
                <CardHeader>
                    <CardTitle>Informasi Produk</CardTitle>
                </CardHeader>
                <CardContent>
                    <ProductInfoSection
                        :form="form"
                        :categories="categories"
                        :category-error="categoryError"
                        @update:name="form.name = $event"
                        @update:description="form.description = $event"
                        @toggle-category="toggleCategory"
                    />
                </CardContent>
            </Card>

            <ProductVariantSection
                v-for="(variant, index) in variants"
                :key="variant.client_id"
                :form="form"
                :variant="variant"
                :index="index"
                :can-remove="variants.length > 1"
                :variant-errors="(clientId, field) => variantErrors(form, clientId, field)"
                @remove="removeVariant(variant.client_id)"
                @update:name="setVariantField(variant.client_id, 'name', $event)"
                @update:stock="setVariantField(variant.client_id, 'stock', $event)"
                @update:retail-stock="setVariantField(variant.client_id, 'retail_stock', $event)"
                @update:media="setVariantField(variant.client_id, 'media', $event)"
            />

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

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