import { createInertiaApp, router } from '@inertiajs/react';
import { LaravelReactI18nProvider, useLaravelReactI18n } from 'laravel-react-i18n';
import { useEffect, useRef, useState } from 'react';
import type { ReactNode } from 'react';
import { toast } from 'sonner';
import { Toaster } from '@/components/ui/sonner';
import { TooltipProvider } from '@/components/ui/tooltip';
import { initializeTheme } from '@/hooks/use-appearance';
import AppLayout from '@/layouts/app-layout';
import AuthLayout from '@/layouts/auth-layout';
import FrontendLayout from '@/layouts/frontend/frontend-layout';
import SettingsLayout from '@/layouts/settings/layout';

let appName = import.meta.env.VITE_APP_NAME || 'Mulai Digital';

/** Auto-derive page title from Inertia component name. */
const PAGE_TITLES: Record<string, string> = {
    dashboard: 'Dashboard',
    'admin/heroes/index': 'Hero Banner',
    'admin/heroes/create': 'Tambah Hero',
    'admin/heroes/edit': 'Ubah Hero',
    'admin/about/index': 'Tentang Kami',
    'admin/services/index': 'Layanan',
    'admin/services/create': 'Tambah Layanan',
    'admin/services/edit': 'Ubah Layanan',
    'admin/testimonials/index': 'Testimoni',
    'admin/testimonials/create': 'Tambah Testimoni',
    'admin/testimonials/edit': 'Ubah Testimoni',
    'frontend/testimonials': 'Testimoni',
    'admin/blog/index': 'Postingan Blog',
    'admin/blog/create': 'Tambah Postingan',
    'admin/blog/edit': 'Ubah Postingan',
    'admin/blog-categories/index': 'Kategori Blog',
    'admin/media/index': 'Media',
    'admin/messages/index': 'Pesan Masuk',
    'admin/messages/show': 'Detail Pesan',
    'admin/visitors/index': 'Pengunjung',
    'admin/users/index': 'Pengguna',
    'admin/users/create': 'Tambah Pengguna',
    'admin/users/edit': 'Ubah Pengguna',
    'admin/roles/index': 'Role & Akses',
    'admin/settings/index': 'Pengaturan',
    'settings/profile': 'Profil',
    'settings/appearance': 'Tampilan',
    'settings/security': 'Keamanan',
};

function resolveTitle(component: string): string {
    // Exact match first
    if (PAGE_TITLES[component]) {
return PAGE_TITLES[component];
}

    // Fallback: derive from path (e.g. 'admin/blog/categories/index' → 'Kategori Blog')
    const parts = component.split('/');

    if (parts.length >= 2) {
        const module = parts[1];
        const action = parts[parts.length - 1];
        const label = module.charAt(0).toUpperCase() + module.slice(1);

        if (action === 'create') {
return `Tambah ${label}`;
}

        if (action === 'edit') {
return `Ubah ${label}`;
}

        if (action === 'show') {
return `Detail ${label}`;
}

        return label;
    }

    return component;
}

type SharedProps = {
    locale?: string;
    flash?: { success?: string; error?: string };
    settings?: { site_name?: string; seo_meta_title?: string };
};

// Sinkronkan locale internal laravel-react-i18n dengan locale aktif.
// Library menginisialisasi state `options` SEKALI via useState — perubahan prop
// `locale` TIDAK otomatis disinkronkan, sehingga `currentLocale()` & `t()`
// membeku di bahasa awal. Komponen ini memanggil `setLocale` bawaan library
// saat locale berubah (guard ref: `setLocale` berganti identitas setiap render
// provider, jadi cukup eksekusi saat locale benar-benar berubah).
function LocaleSyncer({ locale }: { locale: string }) {
    const { setLocale } = useLaravelReactI18n();
    const prevLocale = useRef(locale);

    useEffect(() => {
        if (prevLocale.current === locale) {
            return;
        }

        prevLocale.current = locale;
        setLocale(locale);
    }, [locale, setLocale]);

    return null;
}

// Provider i18n — locale aktif mengikuti navigasi Inertia (SPA visit).
// `usePage()` TIDAK bisa dipakai di level `withApp` (context Inertia ada di
// dalam <App>), jadi locale dibaca dari event `navigate` — selalu fresh.
function I18nProvider({ locale, children }: { locale: string; children: ReactNode }) {
    return (
        <LaravelReactI18nProvider
            locale={locale}
            fallbackLocale="en"
            files={import.meta.glob('/lang/*.json', { eager: true })}
        >
            <LocaleSyncer locale={locale} />
            {children}
        </LaravelReactI18nProvider>
    );
}

function LocaleProvider({ initialLocale, children }: { initialLocale: string; children: ReactNode }) {
    const [locale, setLocale] = useState(initialLocale);

    // Subscribe sekali (tanpa dependency locale) + functional update — hindari
    // teardown/re-subscribe setiap ganti bahasa.
    useEffect(
        () =>
            router.on('navigate', ({ detail }) => {
                const next = (detail.page.props as SharedProps).locale;

                setLocale((prev) => (next && next !== prev ? next : prev));
            }),
        [],
    );

    return <I18nProvider locale={locale}>{children}</I18nProvider>;
}

// Peta komponen halaman → nama form (dipakai untuk pesan toast error spesifik).
const FORM_LABELS: Record<string, string> = {
    'admin/heroes': 'slide hero',
    'admin/about': 'halaman tentang',
    'admin/about/stats': 'statistik',
    'admin/services': 'layanan',
    'admin/testimonials': 'testimoni',
    'admin/blog': 'postingan',
    'admin/blog-categories': 'kategori blog',
    'admin/messages': 'pesan',
    'admin/media': 'media',
    'admin/users': 'pengguna',
    'admin/settings': 'pengaturan',
    'settings/profile': 'profil',
    'settings/appearance': 'tampilan',
    'settings/security': 'keamanan',
};

function resolveFormLabel(component: string): string {
    for (const [prefix, label] of Object.entries(FORM_LABELS)) {
        if (component.startsWith(prefix)) {
            return label;
        }
    }

    return 'data';
}

/**
 * Tentukan aksi form (menyimpan/mengubah/menghapus) dari request terakhir
 * + nama komponen. Error Bag Inertia tidak di-ekspos ke event `error`,
 * jadi aksi disimpulkan dari method & URL visit + komponen halaman.
 */
function resolveFormAction(method: string, url: string, component: string): string {
    if (method === 'DELETE' || url.includes('bulk-destroy')) {
        return 'menghapus';
    }

    if (component.endsWith('/create')) {
        return 'menyimpan';
    }

    if (component.endsWith('/edit')) {
        return 'mengubah';
    }

    if (method === 'PUT' || method === 'PATCH') {
        return 'mengubah';
    }

    // POST dengan id resource di URL (mis. /admin/messages/18) = update status.
    if (method === 'POST' && /\/\d+(\/|$)/.test(url)) {
        return 'mengubah';
    }

    return 'menyimpan';
}

// Flash message (success/error) sebagai toast.
// - Initial load: event `flash` Inertia TIDAK di-fire (top-level flash kosong),
//   jadi toast initial datang dari prop `initialFlash` (flash session biasa).
// - Visit berikutnya: flash session (`->with('success')`) masuk ke
//   `props.flash` di page baru — dibaca lewat event `navigate` (selalu di-fire
//   setelah page swap). Event `flash` Inertia hanya di-fire untuk flash
//   top-level (`Inertia::flash()`), jadi tidak andal untuk flash biasa.
// - Validasi gagal (422): event `error` di-fire → toast error spesifik per
//   aksi (simpan/ubah/hapus) + nama form, dari komponen & request terakhir.
function FlashMessages({ initialFlash, settings }: { initialFlash?: { success?: string; error?: string }; settings?: SharedProps['settings'] }) {
    const shownInitial = useRef(false);
    const lastVisit = useRef<{ method: string; url: string } | null>(null);

    // Sync appName from seo_meta_title for browser tab: "Page | Meta Title"
    useEffect(() => {
        if (settings?.seo_meta_title) {
            appName = settings.seo_meta_title;
        }
    }, [settings]);

    useEffect(() => {
        if (shownInitial.current) {
            return;
        }

        shownInitial.current = true;

        if (initialFlash?.success) {
            toast.success(initialFlash.success);
        }

        if (initialFlash?.error) {
            toast.error(initialFlash.error);
        }
    }, [initialFlash]);

    // Flash fresh per navigasi: event `success` di-fire Inertia pada SETIAP
    // visit yang berhasil (create, update, delete, dsb.) — event `navigate`
    // hanya di-fire saat URL berubah (bukan untuk redirect back() ke URL yang
    // sama), dan event `flash` hanya untuk flash top-level (`Inertia::flash()`),
    // bukan flash session biasa (`->with('success')`) yang masuk ke props.
    // Event awal (initial load) tidak sampai ke sini — ditangani oleh
    // `initialFlash` di atas. Validasi gagal memicu `error` (bukan `success`),
    // jadi tidak ada konflik dengan toast error.
    useEffect(() => router.on('success', ({ detail }) => {
        const flash = (detail.page.props as SharedProps).flash;

        if (flash?.success) {
            toast.success(flash.success);
        }

        if (flash?.error) {
            toast.error(flash.error);
        }
    }), []);

    // Fallback untuk flash top-level (`Inertia::flash()`) bila dipakai.
    useEffect(() => router.on('flash', ({ detail }) => {
        const flash = detail.flash as { success?: string; error?: string };

        if (flash?.success) {
            toast.success(flash.success);
        }

        if (flash?.error) {
            toast.error(flash.error);
        }
    }), []);

    // Rekam request terakhir (method + URL) untuk memetakan aksi saat error.
    useEffect(() => router.on('start', ({ detail }) => {
        const visit = detail.visit as { method?: string; url?: URL };

        lastVisit.current = {
            method: visit.method ?? 'GET',
            url: visit.url ? visit.url.toString() : '',
        };
    }), []);

    useEffect(() => router.on('error', ({ detail }) => {
        const errors = detail.errors as Record<string, string> | undefined;

        if (!errors || Object.keys(errors).length === 0) {
            return;
        }

        // Validasi urutan unik — tampilkan pesan spesifik dari server agar user
        // tahu urutan yang dipakai tidak boleh sama dengan item lain.
        const sortError = errors['sort_order'];

        if (sortError) {
            toast.error(sortError);

            return;
        }

        // Tampilkan pesan error spesifik dari server (validation message)
        // daripada generic "Gagal menyimpan ..."
        const firstError = Object.values(errors)[0];

        if (firstError) {
            toast.error(firstError);
        } else {
            const component = (detail.page?.component as string | undefined) ?? '';
            const label = resolveFormLabel(component);
            const action = resolveFormAction(
                lastVisit.current?.method ?? 'POST',
                lastVisit.current?.url ?? '',
                component,
            );
            toast.error(`Gagal ${action} ${label}. Periksa kembali isian formulir.`);
        }
    }), []);

    return null;
}

createInertiaApp({
    title: (title, { component }) => {
        const pageTitle = title || resolveTitle(component);

        return `${pageTitle} | ${appName}`;
    },
    layout: (name) => {
        switch (true) {
            case name.startsWith('frontend/'):
                return FrontendLayout;
            case name.startsWith('auth/'):
                return AuthLayout;
            case name.startsWith('settings/'):
                return [AppLayout, SettingsLayout];
            default:
                return AppLayout;
        }
    },
    strictMode: true,
    withApp(app, { page }) {
        const props = page.props as SharedProps;

        // Sync appName immediately (before title callback runs)
        if (props.settings?.seo_meta_title) {
            appName = props.settings.seo_meta_title;
        }

        return (
            <LocaleProvider initialLocale={props.locale ?? 'id'}>
                <TooltipProvider delayDuration={0}>
                    {app}
                    <FlashMessages initialFlash={props.flash} settings={props.settings} />
                    <Toaster />
                </TooltipProvider>
            </LocaleProvider>
        );
    },
    progress: {
        color: '#4B5563',
    },
});

// This will set light / dark mode on load...
initializeTheme();
