import { useEffect, useMemo, useRef, useState } from 'react';
import { Link, useForm, useHttp } from '@inertiajs/react';
import { ChevronDown, MapPin, Trash2, Pencil } from 'lucide-react';
import AppLayout from '@/Layouts/AppLayout';
import { useToast } from '@/Components/Toast';
import { cn } from '@/lib/utils';
import { Switch } from '@/Components/ui/switch';
import { FloatingField } from '@/Components/Proto/UI/FloatingField';
import { Pill } from '@/Components/Proto/UI/Pill';
import { SearchableSelect } from '@/Components/Form/SearchableSelect';
import { TutorialPanel, TutorialButton } from '@/Components/Tutorial/TutorialPanel';
import { useTutorial } from '@/lib/tutorials';
import { QuotationProductModal } from '@/Components/MenuQuotations/Quotations/QuotationProductModal';
import { RelatedDocsSection } from '@/Components/MenuQuotations/Quotations/RelatedDocsSection';
import { CustomerArList } from '@/Components/MenuQuotations/CustomerOutstanding/CustomerArList';
import { useCustomerAr } from '@/Hooks/useCustomerAr';
import { footerDefaultId, footerLists } from '@/Components/MenuQuotations/Quotations/footerDefaults';
import { CustomerArAlertModal } from '@/Components/MenuQuotations/CustomerOutstanding/CustomerArAlertModal';
import { arProblems } from '@/Components/MenuQuotations/CustomerOutstanding/arProblems';
import { formatIdr as fmtIdr, formatUsd as fmtUsd } from '@/lib/currencyFormat';
import { useNumberFormat } from '@/Hooks/useNumberFormat';

const SECTION_CARD = 'flex flex-col overflow-visible rounded-xl border border-border bg-card shadow-sm';
const SECTION_HEADER = 'grid grid-cols-[auto_1fr_auto_auto] items-center gap-3 border-b border-border min-h-[66px] p-[18px_24px]';

const STEP_BADGE = 'inline-grid size-8 shrink-0 place-items-center rounded-md bg-accent text-[13px] font-bold tracking-[-0.01em] text-primary';
const SECTION_TITLE = 'm-0 text-base font-bold leading-[1.3] tracking-[-0.005em] text-card-foreground';
const SECTION_SUB = 'mt-0.5 text-[11px] text-muted-foreground';
const PRIMARY_BTN = 'inline-flex h-9 items-center justify-center gap-1.5 rounded-lg bg-linear-to-br from-violet-500 to-primary px-4 text-xs font-bold text-white shadow-sm transition-[filter] hover:brightness-105 disabled:opacity-60';
const SECONDARY_BTN = 'inline-flex h-9 items-center justify-center gap-1.5 rounded-lg border border-input bg-card px-4 text-xs font-bold text-foreground transition-colors hover:border-primary hover:text-primary';
const DATA_BLOCK_LABEL = 'text-[10px] font-extrabold uppercase tracking-[0.025em] text-muted-foreground';
const DATA_BLOCK_TEXT = 'mt-1 min-h-[18px] italic text-muted-foreground';
// Section 4 (PO Details) shares one label/box pair so the header, the left column and the
// Invoice/Delivery blocks all line up — they used three different treatments before.
const FIELD_LABEL = 'text-[11px] font-extrabold uppercase tracking-wide text-muted-foreground';
const FIELD_BOX = 'h-11 w-full rounded-lg border border-input bg-card px-3 text-sm text-foreground outline-none transition-colors focus:border-primary focus:ring-1 focus:ring-primary';
const FieldError = ({ msg }) => (msg ? <p className="mt-1 text-[11px] font-semibold text-danger">{msg}</p> : null);

export default function QuotationsCreate({ companies = [], options, prefill = null, reviseFrom = null, salesPicker = false, salesUsers = [], forOthers = false }) {
    const form = useForm({
        QuotationSubjectID: prefill?.QuotationSubjectID ?? '', QuotationTypeID: prefill?.QuotationTypeID ?? '', QuotationTitleID: prefill?.QuotationTitleID ?? '', QuotationDate: prefill?.QuotationDate ?? '', Comment: prefill?.Comment ?? '',
        CompanyID: prefill?.CompanyID ?? '', CompanyCPID: prefill?.CompanyCPID ?? '', CC: prefill?.CC ?? '',
        USDRate: prefill?.USDRate ?? '',
        CustomerPONo: prefill?.CustomerPONo ?? '', PODate: prefill?.PODate ?? '', IsOrder: prefill?.IsOrder ?? false, DeliveryDate: prefill?.DeliveryDate ?? '',
        InvoiceAddressID: prefill?.InvoiceAddressID ?? '', DeliveryAddressID: prefill?.DeliveryAddressID ?? '',
        // Seeded from FOOTER_DEFAULTS so a fresh form opens with the house terms already in
        // place, instead of six blank required selects that only fill after a Company is picked.
        QuotationPriceDescID: footerDefaultId('QuotationPriceDescID', options, prefill),
        QuotationSalesTermID: footerDefaultId('QuotationSalesTermID', options, prefill),
        QuotationPaymentTermID: footerDefaultId('QuotationPaymentTermID', options, prefill),
        QuotationDeliveryTimeID: footerDefaultId('QuotationDeliveryTimeID', options, prefill),
        QuotationValidityID: footerDefaultId('QuotationValidityID', options, prefill),
        QuotationStockAvailibilityID: footerDefaultId('QuotationStockAvailibilityID', options, prefill),
        UserIDSales: prefill?.UserIDSales ?? '',
        items: prefill?.items ?? [],
    });
    const { data, setData, errors, processing } = form;
    const { show: showToast } = useToast();
    // Resolves by route name, so the "?" appears on quotations.create but NOT on the Revise or
    // Create-for-Others flows this same component also serves — they have no guide of their own.
    const tutorial = useTutorial();
    // Changing the rate re-prices every line already added: UnitPriceIDR is always
    // USD × current rate (whole-rupiah rounding, matching what the product modal emits),
    // so the table, grand total and submit payload follow the latest rate. Rate cleared
    // (or 0) zeroes the IDR prices — same "no rate yet" state as before any rate is set.
    const onRateChange = (raw) => setData((d) => {
        const r = parseFloat(raw) || 0;
        // A change in the STRING that is not a change in the VALUE must not re-price. The 2dp
        // blur padding below rewrites "18000" as "18000.00", and on Revise the stored rate
        // arrives already padded — neither is the user changing the rate. Re-pricing there
        // would overwrite line IDR prices nobody touched, and legacy rows exist whose stored
        // UnitPriceIDR is NOT UnitPriceUSD x rate (quotation 253 stores 23,325,000 where the
        // formula gives 3,147,320), so that overwrite is a silent data change, not a refresh.
        if (r === (parseFloat(d.USDRate) || 0)) return { ...d, USDRate: raw };
        return {
            ...d,
            USDRate: raw,
            items: d.items.map((it) => ({ ...it, UnitPriceIDR: r > 0 ? Math.round((parseFloat(it.UnitPriceUSD) || 0) * r) : 0 })),
        };
    });
    // decimals: 2 — NOT an integer field. quotation.USDRate is decimal(20,10) and 15 of 161
    // live quotations carry cents (15100.99). Leaving it at the default 0 truncated those to
    // 15100 on Revise, and before the parseNumeric fix it magnified them by 10^10 instead.
    const usdRateField = useNumberFormat({ value: data.USDRate, onChange: onRateChange, decimals: 2 });

    const [productModalOpen, setProductModalOpen] = useState(false);
    const [editingLine, setEditingLine] = useState(null); // null = add mode; a line = edit mode

    // Applications are scoped to the selected company's division group
    // (company.DivisionID → division.GroupDivisionID → application.GroupDivisionID) and
    // reloaded whenever the company changes. companyRef gates a late response so a slow
    // reply for a company the user already left can't repopulate the list.
    const appList = useHttp({});
    const [applications, setApplications] = useState([]);
    const companyRef = useRef(data.CompanyID);
    companyRef.current = data.CompanyID;
    useEffect(() => {
        appList.cancel();
        setApplications([]);
        if (!data.CompanyID) return;
        const requestedId = data.CompanyID;
        appList.get(route('quotations.applications.byCompany', { company: requestedId }), {
            onSuccess: (resp) => {
                if (companyRef.current === requestedId) setApplications(Array.isArray(resp) ? resp : []);
            },
        });
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [data.CompanyID]);

    // Company projects for the product modal's To Project picker (legacy
    // getcompanyprojectheaderid.php). Same late-response gating as applications.
    const projList = useHttp({});
    const [projects, setProjects] = useState([]);
    useEffect(() => {
        projList.cancel();
        setProjects([]);
        if (!data.CompanyID) return;
        const requestedId = data.CompanyID;
        projList.get(route('quotations.projects.byCompany', { company: requestedId }), {
            onSuccess: (resp) => {
                if (companyRef.current === requestedId) setProjects(Array.isArray(resp) ? resp : []);
            },
        });
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [data.CompanyID]);

    // Customer Outstanding (AR) — fetched per company from customer-ar.list.byCompany.
    const customerAr = useCustomerAr(data.CompanyID, 'customer-ar.list.byCompany');
    // AR guard — fires ONLY on submit (user decision 2026-08-07: the auto-popup on company
    // select was noise; the moment that matters is the one before the quotation is created).
    const [arAlert, setArAlert] = useState(false);
    const arIssue = arProblems(customerAr.data);

    // Footer terms auto-fill (port of legacy showQuotationHistoryID): on company change,
    // overwrite the six commercial-term selects from the company's last quotation
    // (PaymentTerm may come from its latest finalised credit ceiling — resolved
    // server-side). A history ID is applied only when it still exists in the matching
    // options list; otherwise the list's first option ('' when the list is empty).
    const footerHistory = useHttp({});
    const skipInitialFooter = useRef(reviseFrom != null);
    useEffect(() => {
        footerHistory.cancel();
        if (!data.CompanyID) return;
        // Revise mode: the form is pre-filled with the SOURCE's terms — don't let the
        // first company-driven auto-fill clobber them. Later company changes still fill.
        if (skipInitialFooter.current) { skipInitialFooter.current = false; return; }
        const requestedId = data.CompanyID;
        footerHistory.get(route('quotations.companies.last-footer-terms', { company: requestedId }), {
            onSuccess: (terms) => {
                if (companyRef.current !== requestedId) return;
                const lists = footerLists(options);
                setData((d) => {
                    const next = { ...d };
                    for (const [field, listRaw] of Object.entries(lists)) {
                        const list = listRaw || [];
                        const id = terms?.[field];
                        const valid = id && list.some((o) => o.id === id);
                        next[field] = valid ? String(id) : (list[0] ? String(list[0].id) : '');
                    }
                    return next;
                });
            },
        });
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [data.CompanyID]);

    // Create-for-Others drives the company list from the Sales pick instead of shipping it
    // with the page (legacy createquotationsalesadmin.php renders #InsertCompany with only
    // "Select Company" and fills it from getcompanybysales.php on every #InsertUserIDS
    // change). Every other entry point keeps using the server-supplied list verbatim.
    const [salesCompanies, setSalesCompanies] = useState([]);
    const compBySales = useHttp({});
    const salesRef = useRef(data.UserIDSales);
    salesRef.current = data.UserIDSales;
    useEffect(() => {
        if (!forOthers) return;
        compBySales.cancel();
        setSalesCompanies([]);
        if (!data.UserIDSales) return;
        const requestedSales = data.UserIDSales;
        compBySales.get(route('quotations.companies-by-sales', { sales: requestedSales }), {
            onSuccess: (resp) => {
                // Same late-response gate as the company-driven lookups below: a slow reply
                // for a sales the user already left must not repopulate the list.
                if (salesRef.current === requestedSales) setSalesCompanies(resp?.companies ?? []);
            },
        });
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [data.UserIDSales, forOthers]);
    // Only the for-others path is state-backed; Create and Revise keep reading the server
    // prop directly, so a future partial reload of `companies` still reaches them.
    const companyList = forOthers ? salesCompanies : companies;

    // Legacy appends " (SalesName)" when the company belongs to another sales person
    // (the backend sets salesName only in that case; own companies get null).
    const companyOptions = useMemo(
        () => companyList.map((c) => ({ id: c.id, name: c.salesName ? `${c.name} (${c.salesName})` : c.name })),
        [companyList],
    );
    const selectedCompany = useMemo(() => companyList.find((c) => c.id === data.CompanyID), [companyList, data.CompanyID]);
    const contactOptions = selectedCompany ? selectedCompany.contacts.map((c) => ({ id: c.id, name: c.name })) : [];
    const contactById = (id) => selectedCompany?.contacts.find((c) => c.id === id);

    const rate = parseFloat(data.USDRate) || 0;
    // Subtotals follow legacy semantics: OrderQuantity × unit price. Non-order
    // quotations carry qty 0 on every line, so the grand total reads 0 like legacy.
    const grandUsd = data.items.reduce((s, it) => s + (parseFloat(it.OrderQuantity) || 0) * (parseFloat(it.UnitPriceUSD) || 0), 0);
    const grandIdr = data.items.reduce((s, it) => {
        const q = parseFloat(it.OrderQuantity) || 0;
        const idr = parseFloat(it.UnitPriceIDR) || 0;
        const eff = idr > 0 ? idr : (parseFloat(it.UnitPriceUSD) || 0) * rate;
        return s + q * eff;
    }, 0);

    const onCompanyChange = (id) => {
        setData((d) => ({ ...d, CompanyID: id, CompanyCPID: '', CC: '', InvoiceAddressID: '', DeliveryAddressID: '' }));
    };
    const onContactChange = (id) => {
        setData('CompanyCPID', id);
    };
    // Changing the Sales invalidates the company chosen under the previous one — legacy
    // resets #InsertCompany to 0 and re-fetches the CP list on every #InsertUserIDS change.
    // Revise keeps the plain setter: there the company list is not sales-driven.
    const onSalesChange = (id) => setData((d) => (forOthers
        ? { ...d, UserIDSales: id, CompanyID: '', CompanyCPID: '', CC: '', InvoiceAddressID: '', DeliveryAddressID: '' }
        : { ...d, UserIDSales: id }));

    // An order-flagged subject (quotationsubject.IsOrder) forces the Is Order switch ON;
    // leaving an order subject resets it and clears the order-only fields. A manual ON
    // chosen under a non-order subject is left alone.
    const subjectById = (id) => options.subjects.find((s) => String(s.id) === String(id));
    const subjectForcesOrder = !!Number(subjectById(data.QuotationSubjectID)?.isOrder);
    // Turning Is Order off clears the qty of every line already added — legacy
    // OrderQtyDef() empties all Order Qty inputs when the checkbox is unchecked.
    const clearItemQty = (items) => items.map((x) => ({ ...x, OrderQuantity: 0 }));
    // Menerima id langsung (SearchableSelect), bukan event seperti <select> dulu.
    const onSubjectChange = (id) => {
        setData((d) => {
            const wasForced = !!Number(subjectById(d.QuotationSubjectID)?.isOrder);
            const nowForced = !!Number(subjectById(id)?.isOrder);
            if (nowForced) return { ...d, QuotationSubjectID: id, IsOrder: true };
            if (wasForced) return { ...d, QuotationSubjectID: id, IsOrder: false, DeliveryDate: '', InvoiceAddressID: '', DeliveryAddressID: '', items: clearItemQty(d.items) };
            return { ...d, QuotationSubjectID: id };
        });
    };

    const openAddProduct = () => { setEditingLine(null); setProductModalOpen(true); };
    const openEditProduct = (line) => { setEditingLine(line); setProductModalOpen(true); };
    const closeProductModal = () => { setProductModalOpen(false); setEditingLine(null); };
    // Edit mode replaces the matching line in place (keeping its _id); add mode appends.
    const upsertProduct = (line) => setData('items', editingLine
        ? data.items.map((x) => (x._id === editingLine._id ? { ...line, _id: editingLine._id } : x))
        : [...data.items, line]);
    const removeProduct = (lineId) => setData('items', data.items.filter((x) => x._id !== lineId));

    // Three entry points, three targets: Revise/Recreate, Create for Others (its company
    // gate is inverted, so it cannot share quotations.store), and plain Create.
    const submitTarget = () => {
        if (reviseFrom) return route('quotations.revise.store', reviseFrom);
        if (forOthers) return route('quotations.store-for-others');
        return route('quotations.store');
    };

    const pageTitle = reviseFrom ? 'Revise Quotation' : (forOthers ? 'Create Quotation for Others' : 'Create Quotation');

    // No onSuccess: the server sends the success toast (.claude/rules/notifications.md).
    // onError is mandatory — on a long form the invalid field can be off-screen, and
    // without this the page looks like it simply ignored the click.
    const postQuotation = () => form.post(submitTarget(), {
        onError: () => showToast('Please check the form and try again.', 'error'),
    });

    const submit = (e) => {
        e.preventDefault();
        // Last gate: an AR that is over limit or past due gets stated once more before the
        // quotation is created. It does not BLOCK — the credit call belongs to the approver —
        // but it must not be possible to create one without having seen it.
        if (arIssue.hasProblem) {
            setArAlert(true);
            return;
        }
        postQuotation();
    };


    return (
        <section className={cn('flex min-w-0 flex-col gap-4.5 transition-[margin] duration-200', tutorial.marginClass)}>
            <header className="flex items-center justify-between gap-4">
                <div>
                    <p className="mb-1.5 flex items-center gap-2 text-xs font-semibold text-muted-foreground">
                        <Link href={route('quotations.index')} className="text-muted-foreground no-underline hover:text-primary">Quotations</Link>
                        <span aria-hidden="true">›</span>
                        <span className="text-foreground">{pageTitle}</span>
                    </p>
                    <h1 className="m-0 text-xl font-bold leading-[1.2] text-card-foreground">{reviseFrom ? 'Revise / Recreate Quotation' : pageTitle}</h1>
                </div>
                <div className="flex flex-wrap items-center justify-end gap-2">
                    {/* The v1·v2 switch that used to sit here is GONE (2026-08-11): v2 took over
                        all three real routes and this file is now the frozen v1 reference served
                        only at /proto/quotations/create-v1. Its route target no longer exists, so
                        leaving the switch in place would have been a hard crash, not a dead link. */}
                    {/* Page header, rightmost group, immediately left of Back — the placement
                        rule for this chip. It is size-9, matching the h-9 page-header button
                        height locked in .claude/rules/ui-conventions.md.
                        HIDDEN on user request 2026-08-10 (v1 and v2 alike): `hidden` rather than
                        removal, so re-enabling is deleting one word. The guide itself stays
                        registered and the panel stays wired — it is simply unreachable while the
                        button is display:none. */}
                    {tutorial.guide && <TutorialButton onClick={tutorial.toggle} active={tutorial.isOpen} className="hidden" />}
                    <Link href={route('quotations.index')} className={SECONDARY_BTN}>Back</Link>
                    <button className={SECONDARY_BTN} type="button" onClick={() => form.reset()}>Reset</button>
                </div>
            </header>

            <form className="flex flex-col gap-4.5" onSubmit={submit}>
                <section className="grid items-stretch gap-6 grid-cols-[minmax(0,0.82fr)_minmax(0,1.28fr)] max-[1180px]:grid-cols-1">
                    {/* 1. Quotation Header */}
                    <article className={cn(SECTION_CARD, 'h-full min-w-0')}>
                        <header className={SECTION_HEADER}>
                            <span className={STEP_BADGE}>1</span>
                            <div>
                                <h2 className={SECTION_TITLE}>Quotation Header</h2>
                                <p className={SECTION_SUB}>Basic identification and metadata</p>
                            </div>
                        </header>
                        <div className="flex flex-1 flex-col gap-3.5 p-6">
                            <div className="grid grid-cols-2 gap-3.5 max-[760px]:grid-cols-1">
                                <div data-tut="subject">
                                    <SearchableSelect label="Subject *" placeholder="Select subject" options={options.subjects} value={data.QuotationSubjectID} onChange={onSubjectChange} />
                                    <FieldError msg={errors.QuotationSubjectID} />
                                </div>
                                <div>
                                    <SearchableSelect dataTut="type" label="Type *" placeholder="Select type" options={options.types} value={data.QuotationTypeID} onChange={(v) => setData('QuotationTypeID', v)} />
                                    <FieldError msg={errors.QuotationTypeID} />
                                </div>
                                <div>
                                    <FloatingField data-tut="date" label="Date *" type="date" value={data.QuotationDate} onChange={(e) => setData('QuotationDate', e.target.value)} />
                                    <FieldError msg={errors.QuotationDate} />
                                </div>
                                <div>
                                    <SearchableSelect dataTut="title" label="Quotation Title *" placeholder="Select an option" options={options.titles} value={data.QuotationTitleID} onChange={(v) => setData('QuotationTitleID', v)} />
                                    <FieldError msg={errors.QuotationTitleID} />
                                </div>
                            </div>
                            <div className="w-full">
                                <FloatingField data-tut="comment" as="textarea" label="Comment Internal" rows={2} value={data.Comment} onChange={(e) => setData('Comment', e.target.value)} maxLength={500} />
                            </div>
                        </div>
                    </article>

                    {/* 2. Customer Information */}
                    <article className={cn(SECTION_CARD, 'h-full min-w-0')}>
                        <header className={SECTION_HEADER}>
                            <span className={STEP_BADGE}>2</span>
                            <div>
                                <h2 className={SECTION_TITLE}>Customer Information</h2>
                                <p className={SECTION_SUB}>Buyer company, contact & CC list</p>
                            </div>
                        </header>
                        <div className="flex-1 p-6">
                            <div className="grid items-stretch gap-8 grid-cols-2 max-[760px]:grid-cols-1">
                                <div className="[&>*+*]:mt-3.5">
                                    {/* For Others: Sales comes FIRST and drives the company list —
                                        the reverse of plain Create, where the company decides the
                                        owner. Legacy puts #InsertUserIDS directly above
                                        #InsertCompany for the same reason. */}
                                    {salesPicker && forOthers && (
                                        <div className="mb-3.5">
                                            <SearchableSelect label="Sales Owner *" placeholder="Select sales" options={salesUsers} value={data.UserIDSales} onChange={onSalesChange} />
                                            <FieldError msg={errors.UserIDSales} />
                                        </div>
                                    )}
                                    {/* Group title + pill removed: "Company / Customer" only repeated
                                        the `Company *` field label right beneath it. */}
                                    <SearchableSelect dataTut="company" label="Company *" placeholder={forOthers && !data.UserIDSales ? 'Pilih sales dulu' : 'Select company'} options={companyOptions} value={data.CompanyID} onChange={onCompanyChange} />
                                    <FieldError msg={errors.CompanyID} />
                                    {/* Display read-only — tabIndex={-1} supaya Enter di Company
                                        melompat ke Contact Person, bukan mendarat di kotak yang
                                        tidak bisa diapa-apakan. */}
                                    <div className="mt-3.5 grid grid-cols-2 gap-2.5">
                                        <FloatingField label="Division" type="text" readOnly tabIndex={-1} labelClassName="text-[11px]" value={selectedCompany?.division || ''} />
                                        <FloatingField label="Industry" type="text" readOnly tabIndex={-1} labelClassName="text-[11px]" value={selectedCompany?.industry || ''} />
                                    </div>
                                    <div className="mt-3.5 border-t border-dashed border-border pt-3">
                                        <span className={DATA_BLOCK_LABEL}>Company Address</span>
                                        <p className={DATA_BLOCK_TEXT}>{selectedCompany ? (selectedCompany.address || '—') : 'No company selected'}</p>
                                    </div>
                                </div>
                                <div className="[&>*+*]:mt-3.5">
                                    {/* Same here: "Company CP / Contact" repeated `Contact Person *`. */}
                                    <SearchableSelect dataTut="contact" label="Contact Person *" placeholder={data.CompanyID ? 'Select contact' : 'Pilih company dulu'} options={contactOptions} value={data.CompanyCPID} onChange={onContactChange} />
                                    <FieldError msg={errors.CompanyCPID} />
                                    <div className="mt-3.5 border-t border-dashed border-border pt-3">
                                        <span className={DATA_BLOCK_LABEL}>Address</span>
                                        <p className={DATA_BLOCK_TEXT}>{contactById(data.CompanyCPID)?.address || 'No contact selected'}</p>
                                    </div>
                                    <FloatingField data-tut="cc" label="CC" type="text" value={data.CC} onChange={(e) => setData('CC', e.target.value)} />
                                    {/* Revise-of-an-on-behalf-quotation keeps the picker here: there
                                        the company list is not sales-driven, so the order does not
                                        matter and moving it would shuffle a working form. */}
                                    {salesPicker && !forOthers && (
                                        <div>
                                            <SearchableSelect label="Sales Owner *" placeholder="Select sales" options={salesUsers} value={data.UserIDSales} onChange={onSalesChange} />
                                            <FieldError msg={errors.UserIDSales} />
                                        </div>
                                    )}
                                </div>
                            </div>
                        </div>
                    </article>
                </section>

                <section className="grid items-stretch gap-6 grid-cols-[minmax(0,0.82fr)_minmax(0,1.28fr)] max-[1180px]:grid-cols-1">
                    {/* 3. Exchange Rate */}
                    <article className={cn(SECTION_CARD)}>
                        <header className={SECTION_HEADER}>
                            <span className={STEP_BADGE}>3</span>
                            <div>
                                <h2 className={SECTION_TITLE}>Exchange Rate</h2>
                                <p className={SECTION_SUB}>Set USD to IDR rate before pricing</p>
                            </div>
                        </header>
                        <div className="min-h-[180px] flex-1 p-6">
                            <div className="w-fit">
                                <div className="mb-5 flex w-full items-center gap-2 rounded-md border border-border bg-accent/50 p-[10px_12px] pr-8 font-bold text-primary">
                                    <span className="inline-grid size-4 place-items-center rounded-full border border-current text-[10px]">i</span>
                                    Input kurs sebelum mengisi harga produk
                                </div>
                                <label className="mt-4 block w-full max-w-none" data-tut="usd-rate">
                                    <span className="text-[11px] font-bold text-muted-foreground">USD to IDR Rate *</span>
                                    <div className="mt-1.5 grid grid-cols-[1fr_64px]">
                                        <input type="text" {...usdRateField} placeholder="contoh: 15500" className="h-11 rounded-l-md border border-input bg-card px-2.5 text-right text-sm text-foreground outline-none focus:border-primary focus:ring-1 focus:ring-primary" />
                                        <strong className="grid place-items-center rounded-r-md border border-l-0 border-input bg-accent text-primary">IDR</strong>
                                    </div>
                                </label>
                                <FieldError msg={errors.USDRate} />
                            </div>
                            <div className="mt-3 grid gap-0.5">
                                <span className="text-[9px] font-extrabold uppercase tracking-[0.025em] text-muted-foreground">Preview</span>
                                <strong className="text-[13px] text-card-foreground">$1 = {fmtIdr(rate)}</strong>
                            </div>
                        </div>
                    </article>

                    {/* 4. PO Details */}
                    <article className={cn(SECTION_CARD, 'h-full min-w-0')}>
                        <header className={SECTION_HEADER}>
                            <span className={STEP_BADGE}>4</span>
                            <div>
                                <h2 className={SECTION_TITLE}>PO Details</h2>
                                <p className={SECTION_SUB}>Customer purchase order and shipping</p>
                            </div>
                            {/* Header carries Delivery Date + the Is Order switch, each fenced off by a
                                vertical rule (per the mockup). Delivery Date uses FloatingField like
                                every other date on this form — a bare input with a label stacked above
                                it was the only field here that did not follow the floating-label rule. */}
                            <div className="flex flex-wrap items-stretch justify-end gap-0">
                                {data.IsOrder && (
                                    <div className="flex flex-col justify-center border-l border-border px-6">
                                        <div className="w-[190px]">
                                            <FloatingField data-tut="delivery-date" label="Delivery Date *" type="date" value={data.DeliveryDate}
                                                onChange={(e) => setData('DeliveryDate', e.target.value)} />
                                        </div>
                                        {errors.DeliveryDate && <span className="mt-1 text-[11px] font-semibold text-danger">{errors.DeliveryDate}</span>}
                                    </div>
                                )}
                                <div className="flex items-center gap-3 border-l border-border pl-6" data-tut="is-order">
                                    <span className={FIELD_LABEL}>Is Order</span>
                                    <Switch checked={data.IsOrder} disabled={subjectForcesOrder} onCheckedChange={(next) => setData((d) => ({ ...d, IsOrder: next, DeliveryDate: next ? d.DeliveryDate : '', InvoiceAddressID: next ? d.InvoiceAddressID : '', DeliveryAddressID: next ? d.DeliveryAddressID : '', items: next ? d.items : clearItemQty(d.items) }))} className="data-[state=checked]:bg-success" />
                                    <strong className="text-sm font-bold text-card-foreground">{data.IsOrder ? 'Yes' : 'No'}</strong>
                                </div>
                            </div>
                        </header>
                        <div className="grid min-h-[180px] flex-1 gap-6 p-6 grid-cols-[300px_1fr] max-[1180px]:grid-cols-1">
                            {/* Stacked label-above-input (mockup), not FloatingField: the right-hand
                                column labels its Contact Person the same way, so a floating label on
                                the left would have been the odd pattern out. */}
                            <div className="grid content-start gap-3.5">
                                <FloatingField data-tut="po-number" label="PO Number" type="text" value={data.CustomerPONo} onChange={(e) => setData('CustomerPONo', e.target.value)} />
                                <FloatingField label="PO Date" type="date" value={data.PODate} onChange={(e) => setData('PODate', e.target.value)} />
                                {subjectForcesOrder && <p className="-mt-1 text-[11px] font-semibold text-muted-foreground">Otomatis aktif karena Subject order</p>}
                            </div>
                            <div className="grid content-start gap-4 border-l border-border pl-6 max-[1180px]:border-l-0 max-[1180px]:pl-0">
                                {data.IsOrder ? (
                                    <>
                                        <div className="grid gap-2">
                                            <SearchableSelect dataTut="invoice-contact" label="Invoice · Contact Person" placeholder={data.CompanyID ? 'Select contact' : 'Pilih company dulu'} options={contactOptions} value={data.InvoiceAddressID} onChange={(v) => setData('InvoiceAddressID', v)} />
                                            <div>
                                                <span className={cn(FIELD_LABEL, 'block mb-1')}>Invoice Address</span>
                                                <p className="flex items-start gap-1.5 text-[11px] leading-snug text-foreground">
                                                    <MapPin aria-hidden="true" className="mt-0.5 size-3 shrink-0 text-primary" />
                                                    <span>{contactById(data.InvoiceAddressID)?.address || <span className="italic text-muted-foreground">No address selected</span>}</span>
                                                </p>
                                            </div>
                                        </div>

                                        <div className="grid gap-2 border-t border-dashed border-border pt-4">
                                            <SearchableSelect dataTut="delivery-contact" label="Delivery · Contact Person" placeholder={data.CompanyID ? 'Select contact' : 'Pilih company dulu'} options={contactOptions} value={data.DeliveryAddressID} onChange={(v) => setData('DeliveryAddressID', v)} />
                                            <div>
                                                <span className={cn(FIELD_LABEL, 'block mb-1')}>Delivery Address</span>
                                                <p className="flex items-start gap-1.5 text-[11px] leading-snug text-foreground">
                                                    <MapPin aria-hidden="true" className="mt-0.5 size-3 shrink-0 text-primary" />
                                                    <span>{contactById(data.DeliveryAddressID)?.address || <span className="italic text-muted-foreground">No address selected</span>}</span>
                                                </p>
                                            </div>
                                        </div>
                                    </>
                                ) : (
                                    <div className="flex h-full min-h-[140px] flex-col items-center justify-center rounded-lg border border-dashed border-border bg-accent/30 p-4 text-center">
                                        <span className="text-[11px] font-semibold text-muted-foreground">Is Order = No</span>
                                        <span className="mt-1 text-[10px] italic text-muted-foreground/70">Billing & Shipping details disabled</span>
                                    </div>
                                )}
                            </div>
                        </div>
                    </article>
                </section>

                {/* 5. Product Items */}
                <section className={cn(SECTION_CARD, 'h-full min-w-0')}>
                    <header className={SECTION_HEADER}>
                        <span className={STEP_BADGE}>5</span>
                        <div>
                            <h2 className={SECTION_TITLE}>Product Items</h2>
                            <p className={SECTION_SUB}>Quotation products, pricing and internal remarks</p>
                        </div>
                        <button className={cn(PRIMARY_BTN, 'whitespace-nowrap')} type="button" onClick={openAddProduct} data-tut="add-product">+ Add Product</button>
                    </header>
                    <div className="flex-1 p-6">
                        {data.items.length === 0 && <div className="grid min-h-[72px] place-items-center rounded-md border border-dashed border-input bg-card text-muted-foreground">No Quotation details</div>}
                        {errors.items && <p className="mt-2 text-[11px] font-semibold text-danger">{errors.items}</p>}
                        {data.items.length > 0 && (
                            <div className="overflow-x-auto rounded-md">
                                <table className="w-full min-w-[920px] overflow-hidden rounded-md border-collapse [&_th]:border-b [&_th]:border-border [&_th]:p-2.5 [&_th]:text-left [&_td]:border-b [&_td]:border-border [&_td]:p-2.5 [&_td]:text-left [&_th]:bg-secondary [&_th]:text-muted-foreground [&_th]:text-[10px] [&_th]:font-extrabold [&_th]:uppercase [&_th]:tracking-wide [&_tbody_tr:hover]:bg-secondary/60">
                                    <thead>
                                        <tr>
                                            <th>Principal</th><th>Product</th><th>Packing</th>
                                            <th className="!text-right">Order Qty</th><th className="!text-right">Unit USD</th><th className="!text-right">Subtotal USD</th><th className="!text-right">Unit IDR</th>
                                            <th className="!text-right">Subtotal IDR</th><th>Application</th><th>Remark Quotation</th><th>Project/Remark Int.</th><th>To Project</th><th></th>
                                        </tr>
                                    </thead>
                                    <tbody>
                                        {data.items.map((r) => {
                                            const q = parseFloat(r.OrderQuantity) || 0;
                                            const usd = parseFloat(r.UnitPriceUSD) || 0;
                                            const idr = parseFloat(r.UnitPriceIDR) || 0;
                                            const eff = idr > 0 ? idr : usd * rate;
                                            return (
                                                <tr key={r._id}>
                                                    <td className="text-[11px] text-muted-foreground">{r.PrincipalPrintName || '—'}</td>
                                                    <td className="font-semibold text-foreground">{r.ProductName || '—'}</td>
                                                    <td className="text-[11px] text-muted-foreground">{r._packName || '—'}</td>
                                                    <td className="!text-right tabular-nums">{q ? `${q} ${r._satuanName || ''}`.trim() : '—'}</td>
                                                    <td className="!text-right font-semibold text-foreground tabular-nums">{r.UnitPriceUSD ? fmtUsd(usd) : '—'}</td>
                                                    <td className="!text-right font-semibold text-foreground tabular-nums">{r.UnitPriceUSD ? fmtUsd(q * usd) : '—'}</td>
                                                    <td className="!text-right text-[11px] text-muted-foreground tabular-nums">{idr ? fmtIdr(idr) : '—'}</td>
                                                    <td className="!text-right text-[11px] text-muted-foreground tabular-nums">{fmtIdr(q * eff)}</td>
                                                    <td className="text-[11px] text-muted-foreground">{r._applicationName || '—'}</td>
                                                    <td className="text-[11px] text-muted-foreground">{r.Remarks || '—'}</td>
                                                    <td className="text-[11px] text-muted-foreground">{r.RemarkInternal || '—'}</td>
                                                    <td className="text-[11px] text-muted-foreground">{r.ToProject || '—'}</td>
                                                    <td>
                                                        <div className="flex items-center gap-1">
                                                            <button type="button" className="inline-grid size-[30px] place-items-center rounded-full text-muted-foreground transition-colors hover:bg-secondary hover:text-card-foreground" aria-label="Edit product" onClick={() => openEditProduct(r)}>
                                                                <Pencil className="size-3.5" />
                                                            </button>
                                                            <button type="button" className="inline-grid size-[30px] place-items-center rounded-full text-muted-foreground transition-colors hover:bg-secondary hover:text-card-foreground" aria-label="Remove product" onClick={() => removeProduct(r._id)}>
                                                                <Trash2 className="size-3.5" />
                                                            </button>
                                                        </div>
                                                    </td>
                                                </tr>
                                            );
                                        })}
                                    </tbody>
                                    {/* Grand Total menempel di tabel, bukan kartu terpisah: angkanya
                                        jatuh persis di kolom Subtotal USD / Subtotal IDR yang
                                        menjumlahkannya, sejajar dengan angka per-baris di atasnya. */}
                                    <tfoot>
                                        <tr className="bg-secondary/40 font-extrabold [&_td]:border-b-0 [&_td]:border-t-2 [&_td]:border-border">
                                            <td colSpan={5} className="!text-right text-[11px] uppercase tracking-wide text-muted-foreground">Grand Total</td>
                                            <td className="!text-right text-card-foreground tabular-nums">{fmtUsd(grandUsd)}</td>
                                            <td />
                                            <td className="!text-right text-card-foreground tabular-nums">{fmtIdr(grandIdr)}</td>
                                            <td colSpan={5} />
                                        </tr>
                                    </tfoot>
                                </table>
                            </div>
                        )}
                    </div>
                </section>

                {/* 6. Footer Terms */}
                <section className={cn(SECTION_CARD, 'min-w-0')}>
                    <header className={SECTION_HEADER}>
                        <span className={STEP_BADGE}>6</span>
                        <div>
                            <h2 className={SECTION_TITLE}>Footer</h2>
                            <p className={SECTION_SUB}>Commercial terms</p>
                        </div>
                    </header>
                    <div className="flex-1 p-6">
                        <div className="grid grid-cols-3 gap-3.5 max-[1024px]:grid-cols-2 max-[760px]:grid-cols-1" data-tut="terms">
                            <div>
                                <SearchableSelect label="Price *" placeholder="Select price" options={options.priceDescs} value={data.QuotationPriceDescID} onChange={(v) => setData('QuotationPriceDescID', v)} />
                                <FieldError msg={errors.QuotationPriceDescID} />
                            </div>
                            <div>
                                <SearchableSelect label="Sales Terms *" placeholder="Select sales terms" options={options.salesTerms} value={data.QuotationSalesTermID} onChange={(v) => setData('QuotationSalesTermID', v)} />
                                <FieldError msg={errors.QuotationSalesTermID} />
                            </div>
                            <div>
                                <SearchableSelect label="Payment Terms *" placeholder="Select payment terms" options={options.paymentTerms} value={data.QuotationPaymentTermID} onChange={(v) => setData('QuotationPaymentTermID', v)} />
                                <FieldError msg={errors.QuotationPaymentTermID} />
                            </div>
                            <div>
                                <SearchableSelect label="Delivery / Lead Time *" placeholder="Select delivery time" options={options.deliveryTimes} value={data.QuotationDeliveryTimeID} onChange={(v) => setData('QuotationDeliveryTimeID', v)} />
                                <FieldError msg={errors.QuotationDeliveryTimeID} />
                            </div>
                            <div>
                                <SearchableSelect label="Validity *" placeholder="Select validity" options={options.validities} value={data.QuotationValidityID} onChange={(v) => setData('QuotationValidityID', v)} />
                                <FieldError msg={errors.QuotationValidityID} />
                            </div>
                            <div>
                                <SearchableSelect label="Stock Availability *" placeholder="Select stock availability" options={options.stockAvailabilities} value={data.QuotationStockAvailibilityID} onChange={(v) => setData('QuotationStockAvailibilityID', v)} />
                                <FieldError msg={errors.QuotationStockAvailibilityID} />
                            </div>
                        </div>
                    </div>
                </section>

                {/* Customer Outstanding (AR) — wired to customer-ar.list.byCompany */}
                <div data-tut="customer-ar"><CustomerArList data={customerAr.data} loading={customerAr.loading} /></div>

                {/* Link Related Documents — read-only display of the company's related docs */}
                <RelatedDocsSection companyId={data.CompanyID} />

                <div className="flex items-center justify-between gap-4 pb-2">
                    <div className="flex flex-wrap gap-2.5">
                        <button className={PRIMARY_BTN} type="submit" disabled={processing} data-tut="submit">{processing ? 'Saving…' : 'Create Quotation'}</button>
                    </div>
                    <Link href={route('quotations.index')} className={SECONDARY_BTN}>Cancel</Link>
                </div>
                <CustomerArAlertModal
                    open={arAlert}
                    data={customerAr.data}
                    processing={processing}
                    onClose={() => setArAlert(false)}
                    onConfirm={() => { setArAlert(false); postQuotation(); }}
                />
            </form>

            <QuotationProductModal open={productModalOpen} onClose={closeProductModal} onAccept={upsertProduct} initial={editingLine} options={options} applications={applications} projects={projects} usdRate={rate} companyId={data.CompanyID} isOrder={data.IsOrder} />

            {/* Rendered after the modal so that, at equal z-index, the panel would still win —
                though it does not have to: the panel sits at z-[60], the modal overlay at z-50. */}
            {tutorial.guide && <TutorialPanel open={tutorial.isOpen} onClose={tutorial.close} {...tutorial.guide} />}
        </section>
    );
}

QuotationsCreate.layout = [AppLayout];
