<script setup lang="ts">
import { useForm } from '@inertiajs/vue3';
import { Plus, Save } from '@lucide/vue';
import { computed, ref } from 'vue';
import { toast } from 'vue-sonner';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { useCan } from '@/composables/useCan';
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 { hasRole } = useCan();
const showPrices = !hasRole('admin-bahan-baku');

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 isUploading = computed(() => 
    variants.value.some((v) => v.media.pendingUploads > 0)
);

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

        return props.initialData.variants.map((variant) => {
            const prices: Record<string, string> = {
                distributor: '0',
                agent: '0',
                sub_agent: '0',
                grosir: '0',
                retail: '0',
                tiktok: '0',
                shopee: '0',
                harga_modal: '0',
            };
            variant.prices?.forEach((price) => {
                if (price.type) {
                    prices[price.type] = String(price.price);
                }
            });
            return {
                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',
                prices,
                media: createMediaUploadState(variant.images ?? []),
            };
        });
    },
);

const copiedPrices = ref<Record<string, string> | null>(null);

function copyPrices(variantPrices: Record<string, string>) {
    copiedPrices.value = { ...variantPrices };
}

function pastePrices(clientId: string) {
    if (!copiedPrices.value) return;
    setVariantField(clientId, 'prices', { ...copiedPrices.value });
}

function applyToAllPrices(variantPrices: Record<string, string>) {
    variants.value.forEach((v) => {
        setVariantField(v.client_id, 'prices', { ...variantPrices });
    });
}

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));
        if (variant.prices && showPrices) {
            Object.entries(variant.prices as Record<string, string>).forEach(([type, value]) => {
                formData.append(`variants[${index}][prices][${type}]`, String(Number.parseInt(value, 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"
                :has-copied-prices="!!copiedPrices"
                :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:prices="setVariantField(variant.client_id, 'prices', $event)"
                @update:media="setVariantField(variant.client_id, 'media', $event)"
                @copy-prices="copyPrices(variant.prices as Record<string, string>)"
                @paste-prices="pastePrices(variant.client_id)"
                @apply-to-all-prices="applyToAllPrices(variant.prices as Record<string, string>)"
            />

            <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 || isUploading">
                    <Save class="size-4" />
                    {{ isUploading ? 'Mengunggah...' : form.processing ? 'Menyimpan...' : submitLabel }}
                </Button>
            </div>
        </div>
    </form>
</template>
