<script setup lang="ts">
import { useForm } from '@inertiajs/vue3';
import { FileText, Globe, 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 { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Switch } from '@/components/ui/switch';
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 = computed(() => !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',
        reject_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',
                reject_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',
                reject_stock: variant.reject_stock != null ? String(variant.reject_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);

const variantSearchQuery = ref('');

function shouldShowVariant(variant: ProductVariantFormItem, index: number) {
    const hasError = Object.keys(form.errors).some((key) => key.startsWith(`variants.${index}.`));

    if (hasError) {
        return true;
    }

    const query = variantSearchQuery.value.trim().toLowerCase();

    if (!query) {
        return true;
    }

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

const hasVisibleVariants = computed(() => {
    return variants.value.some((variant, index) => shouldShowVariant(variant, index));
});

function handleAddVariant() {
    variantSearchQuery.value = '';
    addVariant();
}

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 showDeleteConfirm = ref(false);
const variantToDelete = ref<string | null>(null);

function confirmRemoveVariant(clientId: string) {
    variantToDelete.value = clientId;
    showDeleteConfirm.value = true;
}

function handleRemoveVariant() {
    if (variantToDelete.value) {
        removeVariant(variantToDelete.value);
        variantToDelete.value = null;
    }

    showDeleteConfirm.value = false;
}

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

const isDraft = ref(props.initialData?.status === 'draft');

function toggleDraft(checked: boolean) {
    isDraft.value = checked;
    form.status = checked ? 'draft' : 'active';
}

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());
    formData.append('status', form.status);

    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}][reject_stock]`, String(Number.parseInt(String(variant.reject_stock), 10) || 0));
        formData.append(`variants[${index}][retail_stock]`, String(Number.parseInt(String(variant.retail_stock), 10) || 0));

        if (variant.prices && showPrices.value) {
            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>

            <!-- Section pencarian varian -->
            <div v-if="variants.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 ({{ variants.length }})</h3>
                <div v-if="variants.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>

            <ProductVariantSection v-for="(variant, index) in variants" :key="variant.client_id"
                v-show="shouldShowVariant(variant, index)" :form="form" :variant="variant" :index="index"
                :can-remove="variants.length > 1" :has-copied-prices="!!copiedPrices" :show-prices="showPrices"
                :variant-errors="(clientId, field) => variantErrors(form, clientId, field)"
                @remove="confirmRemoveVariant(variant.client_id)"
                @update:name="setVariantField(variant.client_id, 'name', $event)"
                @update:stock="setVariantField(variant.client_id, 'stock', $event)"
                @update:reject-stock="setVariantField(variant.client_id, 'reject_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 v-if="variants.length > 0 && !hasVisibleVariants"
                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>

            <div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
                <Button type="button" variant="outline" @click="handleAddVariant">
                    <Plus class="size-4" />
                    Tambah Varian
                </Button>

                <div class="flex flex-col items-end gap-3 sm:flex-row sm:items-center sm:gap-4">
                    <div class="flex items-center gap-2">
                        <Switch :id="'draft-toggle'" :model-value="isDraft" @update:model-value="toggleDraft" />
                        <Label :for="'draft-toggle'" class="cursor-pointer">
                            <span class="flex items-center gap-1.5 text-sm whitespace-nowrap">
                                <FileText v-if="isDraft" class="size-4 text-muted-foreground" />
                                <Globe v-else class="size-4 text-muted-foreground" />
                                {{ isDraft ? 'Simpan sebagai Draft' : 'Publikasikan' }}
                            </span>
                        </Label>
                    </div>

                    <Button type="submit" :disabled="form.processing || isUploading" class="w-full sm:w-auto">
                        <Save class="size-4" />
                        {{ isUploading ? 'Mengunggah...' : form.processing ? 'Menyimpan...' : submitLabel }}
                    </Button>
                </div>
            </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="handleRemoveVariant" />
</template>
