import AppLayout from '@/Layouts/AppLayout'
import { TopBar, Crumb, CrumbSep, CrumbCurrent } from '@/Components/Table'
import { useCustomBoard } from '@/Components/CustomBoard'
import {
    KpiStrip, RevenueTrendCard, TopPrincipalsCard, RecentUnifiedCard, SalesPodiumHero,
    ScopeSwitcher, ScopeBar, BirthdaysCard, ApprovalShortcutsCard,
} from '@/Components/Dashboard/widgets'

/**
 * Dashboard — the REAL landing board. Every widget shows the figures of the ACTIVE SCOPE
 * (DashboardWidgetService + DashboardScope): own rows for sales, the headed divisions for an SM,
 * the headed principals for a PM. The layout is per-user customizable via the CustomBoard engine
 * promoted from the proto (✎ atur di board + ⚙ modal, urutan/lebar/sembunyi tersimpan di
 * localStorage per halaman) — layout prefs are shared across scopes on purpose: it is the same
 * board, only the numbers change.
 *
 * Path stays Pages/Dashboard/Index.jsx (Inertia v3 path resolution) with layout = [AppLayout];
 * this page also remains the design-token visual reference per design-system.md.
 */
export default function Dashboard({
    scope, kpis = null, revenueTrend = null, recent = null, podium = null, topPrincipal = null,
    approvals = [], birthdays = [], birthdayCalendar = null,
    // Per-ROLE ceiling from App\Support\DashboardWidgets. A widget the role cannot see has no
    // prop at all — these defaults exist so the page renders instead of throwing on the absence.
    allowedWidgets = null,
}) {
    const ALL_WIDGETS = [
        { id: 'kpis', label: 'Ringkasan KPI', spans: [12], defaultSpan: 12, render: () => <KpiStrip kpis={kpis} /> },
        // Podium (8) + Top Principal (4) = 12, so they share row two. They MUST be adjacent in
        // this array: `trend` (6) used to sit between them, and 8 + 6 does not fit in a 12-col
        // grid — trend wrapped to its own row and Top Principal ended up beside it instead. The
        // comment claimed the pairing while the order prevented it, and `spanOverride` below
        // (podium → 12 when principal is hidden) assumed it too.
        // UNCONDITIONAL in this array, for every user (user decision 2026-08-24). Between
        // 2026-08-23 and 2026-08-24 this entry was spread in only when the server sent a non-null
        // `podium`, which it withheld from anyone who had never owned a quotation. ⛔ Do not put
        // that back: it also took the widget out of the ⚙ modal, so those users had no way to ask
        // for it either. The podium is a company scoreboard; being able to see where the company
        // stands is the point, and `podium.sales` being an empty list already renders an honest
        // empty card. Whether the card exists at all is decided ONCE, by the role's grant, in the
        // allowedWidgets filter below — not by guessing from the data.
        { id: 'podium', label: 'Podium Penjualan', spans: [7, 8, 12], defaultSpan: 7, render: () => <SalesPodiumHero podium={podium} /> },
        // `topPrincipal`, NOT `recent.principal`: the two are separate grants, so a role holding
        // `principal` without `recent` gets no `recent` prop at all and reading through it threw.
        // The fallback covers the reverse order — an older payload that only carried the nested one.
        { id: 'principal', label: 'Top Principal', spans: [4, 5, 6], defaultSpan: 5, render: () => <TopPrincipalsCard rows={topPrincipal ?? recent?.principal ?? []} /> },
        // Every row must sum to 12. Omset (8) + Approval (4) = 12; Transaksi (8) + Ulang
        // Tahun (4) = 12. When they summed to 10 the grid left a two-column dead band on the
        // right of both rows — the board looked narrower than the rows above it.
        // Shortcuts, not figures — they stay put whichever scope is active.
        { id: 'trend', label: 'Omset 12 Bulan', spans: [6, 7, 8, 12], defaultSpan: 7, render: () => <RevenueTrendCard trend={revenueTrend} /> },
        { id: 'approvals', label: 'Approval', spans: [4, 5, 6], defaultSpan: 5, render: () => <ApprovalShortcutsCard approvals={approvals} /> },
        { id: 'recent', label: 'Transaksi Terbaru', spans: [6, 7, 8, 12], defaultSpan: 7, render: () => <RecentUnifiedCard recent={recent} /> },
        // Last row, full width. Company-wide (not scoped), so it stays put whichever scope is on.
        { id: 'birthdays', label: 'Ulang Tahun', spans: [4, 5, 6], defaultSpan: 5, render: () => <BirthdaysCard calendar={birthdayCalendar} /> },
    ]

    // The role's grants are a CEILING; the personal layout works inside it. Same shape as
    // useColumnPrefs dropping stored column ids it no longer recognises — a saved layout that
    // still names a revoked widget simply loses that entry, and the stored order/width the
    // user chose for everything else survives. `allowedWidgets = null` means an older payload
    // (or a page rendered before this shipped): fall back to showing everything rather than a
    // blank board.
    const WIDGETS = allowedWidgets === null
        ? ALL_WIDGETS
        : ALL_WIDGETS.filter((w) => allowedWidgets.includes(w.id));

    const { controls, board } = useCustomBoard({
        // _v4: Omset↔Approval swap. The ORDER is persisted (useColumnPrefs keeps a stored payload and only appends
        // ids it has never seen), so fixing the array above would have changed nothing for
        // anyone who had already opened this page — their old order would keep winning. The
        // spans key is deliberately NOT bumped: widths were not wrong, and re-bumping it would
        // throw away a width the user chose on purpose.
        prefsKey: 'dashboardWidgets_v4',
        spansKey: 'dashboardWidgets_spans_v3',
        widgets: WIDGETS,
        // Responsive override to expand cards to full width (12) when their row partner is hidden,
        // avoiding blank gaps.
        spanOverride: (id, visibleIds) => {
            if (id === 'podium' && !visibleIds.has('principal')) return 12;
            // Without the podium the row pairing shifts up by one and Ulang Tahun is left alone on
            // the last row at span 5, with a seven-column dead band beside it. The server no longer
            // withholds the podium per USER, so there are exactly two ways here: the role does not
            // hold the `podium` grant (or holds it without `money` — it is money-only), or the user
            // hid it in the ⚙ modal. Same arithmetic either way.
            if (id === 'birthdays' && !visibleIds.has('podium')) return 12;
            if (id === 'trend' && !visibleIds.has('recent')) return 12;
            if (id === 'recent' && !visibleIds.has('trend')) return 12;
            return null;
        },
    })

    return (
        // No currency prop and no provider: every figure the server sends is IDR, as stored, and
        // stays IDR on the screen. The flat USD_IDR_RATE that used to be threaded through here was
        // one invented number — see the money block in Components/Dashboard/widgets.jsx.
        <section className="flex flex-col gap-4">
            {/* TopBar carries its own mb-[18px], which suits pages whose next block is a card.
                Here the scope line is a CONTINUATION of the heading, so that margin plus the
                section's gap-4 put 34px above the line while only ~12px sat below it — it read
                as a caption for the KPI strip rather than for the title. Cancelled inside this
                group and replaced with a 6px gap; the shared TopBar is left alone for the ~40
                other pages that rely on it. */}
            <div className="flex flex-col gap-1.5 [&>header]:mb-0">
            <TopBar
                title="Dashboard"
                breadcrumb={
                    <>
                        <Crumb href={route('dashboard')}>Dashboard</Crumb>
                        <CrumbSep />
                        <CrumbCurrent>Overview</CrumbCurrent>
                    </>
                }
                action={
                    <div className="flex flex-wrap items-center justify-end gap-2">
                        <ScopeSwitcher scope={scope} />
                        {controls}
                    </div>
                }
            />
            <ScopeBar scope={scope} />
            </div>
            {board}
        </section>
    )
}

Dashboard.layout = [AppLayout]
