<script setup lang="ts">
import { useForm } from '@inertiajs/vue3';
import { Copy, Plus, Save, Trash2 } from '@lucide/vue';
import { ref } from 'vue';
import { toast } from 'vue-sonner';
import { DecimalInput } from '@/components/form/decimal-input';
import { MultipleImageUploadField } from '@/components/form/image-upload-field';
import { RupiahInput } from '@/components/form/rupiah-input';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import {
    Field,
    FieldError,
    FieldGroup,
    FieldLabel,
    FieldSet,
} from '@/components/ui/field';
import { Input } from '@/components/ui/input';
import {
    Select,
    SelectContent,
    SelectItem,
    SelectTrigger,
    SelectValue,
} from '@/components/ui/select';
import { FIELD_LIMITS } from '@/lib/field-limits';
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';

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()}`;
}

function createEmptyPrice(): RawMaterialPriceFormItem {
    return {
        client_id: createClientId(),
        variant: '',
        price: '',
        stock: '0',
        media: createMediaUploadState(),
    };
}

function buildInitialPrices(): RawMaterialPriceFormItem[] {
    if (!props.initialData?.prices?.length) {
        return [createEmptyPrice()];
    }

    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 prices = ref<RawMaterialPriceFormItem[]>(buildInitialPrices());
const useSamePrice = ref(prices.value.length <= 1 || allPricesHaveSameValue(prices.value));

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

function allPricesHaveSameValue(items: RawMaterialPriceFormItem[]): boolean {
    if (items.length <= 1) {
        return true;
    }

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

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

function addPrice() {
    const newPrice = createEmptyPrice();

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

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

function removePrice(clientId: string) {
    if (prices.value.length <= 1) {
        return;
    }

    prices.value = prices.value.filter((price) => price.client_id !== clientId);
}

function setPriceField(clientId: string, key: 'variant' | 'stock', value: string) {
    prices.value = prices.value.map((price) =>
        price.client_id === clientId ? { ...price, [key]: value } : price,
    );
}

function setPriceValue(clientId: string, value: string) {
    prices.value = prices.value.map((price) =>
        price.client_id === clientId ? { ...price, price: value } : price,
    );
}

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();

    if (props.method === 'put') {
        formData.append('_method', 'PUT');
    }

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

    prices.value.forEach((price, index) => {
        if (price.id) {
            formData.append(`prices[${index}][id]`, String(price.id));
        }

        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);
    });

    return formData;
}

function formError(key: string): string | undefined {
    return (form.errors as Record<string, string>)[key];
}

function priceError(clientId: string, field: string): string | undefined {
    const index = prices.value.findIndex((price) => price.client_id === clientId);

    if (index === -1) {
        return undefined;
    }

    return formError(`prices.${index}.${field}`);
}

function submit() {
    const options = {
        forceFormData: true,
        onError: () => {
            toast.error('Gagal menyimpan data. Periksa kembali formulir.');
        },
    };

    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 Bahan Baku</CardTitle>
                </CardHeader>
                <CardContent>
                    <FieldGroup>
                        <FieldSet class="grid gap-4 md:grid-cols-2">
                            <Field>
                                <FieldLabel for="name" required>Nama Bahan Baku</FieldLabel>
                                <Input id="name" v-model="form.name" type="text" placeholder="Masukkan nama bahan baku"
                                    :maxlength="FIELD_LIMITS.name" />
                                <FieldError :errors="formErrors(form, 'name')" />
                            </Field>

                            <Field>
                                <FieldLabel for="unit" required>Satuan</FieldLabel>
                                <Select v-model="form.unit">
                                    <SelectTrigger id="unit" class="w-full">
                                        <SelectValue placeholder="Pilih satuan" />
                                    </SelectTrigger>
                                    <SelectContent>
                                        <SelectItem v-for="option in units" :key="option.value" :value="option.value">
                                            {{ option.label }}
                                        </SelectItem>
                                    </SelectContent>
                                </Select>
                                <FieldError :errors="formErrors(form, 'unit')" />
                            </Field>
                        </FieldSet>
                    </FieldGroup>
                </CardContent>
            </Card>

            <Card v-if="prices.length > 1">
                <CardHeader>
                    <CardTitle>Harga Bersama</CardTitle>
                </CardHeader>
                <CardContent>
                    <FieldGroup>
                        <label class="mb-4 flex cursor-pointer items-center gap-2">
                            <input type="checkbox" class="size-4 rounded border-input" :checked="useSamePrice"
                                @change="toggleUseSamePrice(($event.target as HTMLInputElement).checked)">
                                <span class="text-sm">Gunakan harga yang sama untuk semua varian</span>
                        </label>

                        <Field v-if="useSamePrice && prices[0]">
                            <FieldLabel :for="`shared_price_${prices[0].client_id}`" required>
                                Harga
                            </FieldLabel>
                            <RupiahInput :id="`shared_price_${prices[0].client_id}`" :model-value="prices[0].price"
                                @update:model-value="setSharedPrice" />
                            <FieldError
                                :errors="priceError(prices[0].client_id, 'price') ? [priceError(prices[0].client_id, 'price')!] : []" />
                        </Field>
                    </FieldGroup>
                </CardContent>
            </Card>

            <Card v-for="(price, index) in prices" :key="price.client_id">
                <CardHeader class="flex flex-row items-start justify-between gap-4">
                    <CardTitle>Varian {{ index + 1 }}</CardTitle>
                    <div class="flex items-center gap-2">
                        <Button v-if="prices.length > 1 && !useSamePrice" type="button" variant="outline" size="sm"
                            @click="applyPriceToAllVariants(price.client_id)">
                            <Copy class="size-4" />
                            Terapkan Harga ke Semua
                        </Button>
                        <Button v-if="prices.length > 1" type="button" variant="outline" size="icon"
                            class="text-destructive hover:text-destructive size-8"
                            @click="removePrice(price.client_id)">
                            <Trash2 class="size-4" />
                        </Button>
                    </div>
                </CardHeader>
                <CardContent>
                    <FieldGroup>
                        <FieldSet class="grid gap-4 md:grid-cols-3">
                            <Field>
                                <FieldLabel :for="`variant_${price.client_id}`" required>
                                    Nama Varian
                                </FieldLabel>
                                <Input :id="`variant_${price.client_id}`" :model-value="price.variant" type="text"
                                    placeholder="Contoh: Premium / 40s" :maxlength="FIELD_LIMITS.variantName"
                                    @update:model-value="setPriceField(price.client_id, 'variant', String($event))" />
                                <FieldError
                                    :errors="priceError(price.client_id, 'variant') ? [priceError(price.client_id, 'variant')!] : []" />
                            </Field>
                            <Field>
                                <FieldLabel :for="`stock_${price.client_id}`" required>
                                    Stok
                                </FieldLabel>
                                <DecimalInput :id="`stock_${price.client_id}`" :model-value="price.stock"
                                    @update:model-value="setPriceField(price.client_id, 'stock', String($event))" />
                                <FieldError
                                    :errors="priceError(price.client_id, 'stock') ? [priceError(price.client_id, 'stock')!] : []" />
                            </Field>
                            <Field v-if="!useSamePrice || prices.length === 1">
                                <FieldLabel :for="`price_${price.client_id}`" required>
                                    Harga
                                </FieldLabel>
                                <RupiahInput :id="`price_${price.client_id}`" :model-value="price.price"
                                    @update:model-value="setPriceValue(price.client_id, $event)" />
                                <FieldError
                                    :errors="priceError(price.client_id, 'price') ? [priceError(price.client_id, 'price')!] : []" />
                            </Field>
                        </FieldSet>

                        <div class="mt-4">
                            <MultipleImageUploadField :id="`price_images_${price.client_id}`" v-model="price.media"
                                label="Foto Varian" :max-files="5" required
                                :errors="priceError(price.client_id, 'images') ? [priceError(price.client_id, 'images')!] : []" />
                        </div>
                    </FieldGroup>
                </CardContent>
            </Card>

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

            <div class="flex items-center justify-between gap-2">
                <Button type="button" variant="outline" @click="addPrice">
                    <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>
