import { App as AntApp, Button, ConfigProvider, Result, Skeleton } from 'antd';
import { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react';
import {
  createBrowserRouter,
  createRoutesFromElements,
  Navigate,
  Outlet,
  Route,
  RouterProvider,
  useLocation,
  useNavigationType
} from 'react-router-dom';

import { AdminLayout } from '../layouts/AdminLayout';
import { AppContext, useAppContext } from './app-context';
import { I18nProvider, useI18n } from './i18n/react';
import { api } from './services/api';
import './styles.css';
import { mailhubTheme } from './theme';
import type { RuntimeConfig, User } from './types';

const Dashboard = lazy(() => import('../pages/Dashboard'));
const Domains = lazy(() => import('../pages/Domains'));
const DomainDetail = lazy(() => import('../pages/Domains/DomainDetail'));
const SendingLogs = lazy(() => import('../pages/SendingLogs'));
const Inbox = lazy(() => import('../pages/Inbox'));
const SmtpCredentials = lazy(() => import('../pages/SmtpCredentials'));
const ApiTokens = lazy(() => import('../pages/ApiTokens'));
const Webhooks = lazy(() => import('../pages/Webhooks'));
const DnsApi = lazy(() => import('../pages/DnsApi'));
const Admin = lazy(() => import('../pages/Admin'));
const Settings = lazy(() => import('../pages/Settings'));

const router = createBrowserRouter(createRoutesFromElements(
  <Route element={<ConsoleBootstrap />}>
    <Route element={<AdminLayout />}>
      <Route index element={<Navigate to="/overview" replace />} />
      <Route path="overview" element={<RoutePage><Dashboard /></RoutePage>} />
      <Route path="activity" element={<RoutePage><SendingLogs /></RoutePage>} />
      <Route path="activity/:eventId" element={<RoutePage><SendingLogs /></RoutePage>} />
      <Route path="domains" element={<RoutePage><Domains /></RoutePage>} />
      <Route path="domains/:id/:section" element={<RoutePage><DomainDetail /></RoutePage>} />
      <Route path="inbox" element={<RoutePage><Inbox /></RoutePage>} />
      <Route path="inbox/messages/:messageId" element={<RoutePage><Inbox /></RoutePage>} />
      <Route path="integrations/smtp" element={<RoutePage><SmtpCredentials /></RoutePage>} />
      <Route path="integrations/api-keys" element={<RoutePage><ApiTokens /></RoutePage>} />
      <Route path="integrations/webhooks" element={<RoutePage><Webhooks /></RoutePage>} />
      <Route path="integrations/dns" element={<RoutePage><DnsApi /></RoutePage>} />
      <Route element={<AdminOnly />}>
        <Route path="admin" element={<Navigate to="/admin/users" replace />} />
        <Route path="admin/:section" element={<RoutePage><Admin /></RoutePage>} />
        <Route path="settings" element={<RoutePage><Settings /></RoutePage>} />
      </Route>
      <Route path="*" element={<NotFound />} />
    </Route>
  </Route>
));

export default function App() {
  return (
    <ConfigProvider theme={mailhubTheme}>
      <AntApp>
        <I18nProvider>
          <RouterProvider router={router} />
        </I18nProvider>
      </AntApp>
    </ConfigProvider>
  );
}

function ConsoleBootstrap() {
  const { t } = useI18n();
  const [user, setUser] = useState<User | null>(null);
  const [config, setConfig] = useState<RuntimeConfig | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState('');

  const loadBootstrap = useCallback(async () => {
    setLoading(true);
    setError('');
    try {
      const [meResult, configResult] = await Promise.all([api.me(), api.config()]);
      setUser(meResult.user);
      setConfig(configResult);
    } catch (reason) {
      const nextError = reason instanceof Error ? reason.message : '操作失败';
      if (/Authentication required/i.test(nextError)) {
        window.location.assign(loginPathForCurrentLocation());
        return;
      }
      setError(nextError);
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    void loadBootstrap();
  }, [loadBootstrap]);

  const logout = useCallback(async () => {
    await api.logout().catch(() => null);
    window.location.assign('/login');
  }, []);

  const context = useMemo(() => ({
    user,
    config,
    refreshBootstrap: loadBootstrap,
    logout
  }), [config, loadBootstrap, logout, user]);

  if (loading) return <BootstrapSkeleton />;

  if (error || !user || !config) {
    return (
      <Result
        status="error"
        title={t('shell.loadingFailed')}
        subTitle={error || t('common.error')}
        extra={[
          <Button type="primary" key="retry" onClick={() => void loadBootstrap()}>
            {t('shell.retry')}
          </Button>,
          <Button key="login" href={loginPathForCurrentLocation()}>
            {t('shell.backToLogin')}
          </Button>
        ]}
      />
    );
  }

  return (
    <AppContext.Provider value={context}>
      <ScrollRestoration />
      <Outlet />
    </AppContext.Provider>
  );
}

function AdminOnly() {
  const { user } = useAppContext();
  const { t } = useI18n();
  if (user?.role !== 'admin') {
    return (
      <Result
        status="403"
        title={t('shell.forbiddenTitle')}
        subTitle={t('shell.forbiddenDescription')}
        extra={<Button type="primary" href="/overview">{t('shell.backOverview')}</Button>}
      />
    );
  }
  return <Outlet />;
}

function RoutePage({ children }: { children: ReactNode }) {
  return <Suspense fallback={<PageSkeleton />}>{children}</Suspense>;
}

function NotFound() {
  const { t } = useI18n();
  return (
    <Result
      status="404"
      title={t('shell.notFoundTitle')}
      subTitle={t('shell.notFoundDescription')}
      extra={<Button type="primary" href="/overview">{t('shell.backOverview')}</Button>}
    />
  );
}

function BootstrapSkeleton() {
  const { t } = useI18n();
  return (
    <div className="bootstrap-skeleton" aria-label={t('shell.loadingConsole')}>
      <div className="bootstrap-skeleton__sidebar" />
      <div className="bootstrap-skeleton__content">
        <Skeleton active paragraph={{ rows: 8 }} />
      </div>
    </div>
  );
}

function PageSkeleton() {
  const { t } = useI18n();
  return (
    <div className="route-skeleton" aria-label={t('shell.loadingPage')}>
      <Skeleton active title={{ width: '32%' }} paragraph={{ rows: 7 }} />
    </div>
  );
}

function ScrollRestoration() {
  const location = useLocation();
  const navigationType = useNavigationType();
  const previousScope = useRef<string | null>(null);

  useEffect(() => {
    const storageKey = `mailhub.scroll.${location.key}`;
    const scope = routeScrollScope(location.pathname);
    const keepPosition = previousScope.current === scope;
    const top = keepPosition
      ? window.scrollY
      : navigationType === 'POP'
        ? Number(window.sessionStorage.getItem(storageKey) || 0)
        : 0;
    previousScope.current = scope;
    const frame = window.requestAnimationFrame(() => {
      if (!keepPosition) window.scrollTo({ top, behavior: 'auto' });
    });
    return () => {
      window.cancelAnimationFrame(frame);
      window.sessionStorage.setItem(storageKey, String(window.scrollY));
    };
  }, [location.key, navigationType]);

  return null;
}

function routeScrollScope(pathname: string) {
  if (/^\/activity(?:\/|$)/.test(pathname)) return '/activity';
  if (/^\/inbox(?:\/|$)/.test(pathname)) return '/inbox';
  return pathname;
}

function loginPathForCurrentLocation() {
  const current = `${window.location.pathname}${window.location.search}${window.location.hash}`;
  const next = current.startsWith('/') && !current.startsWith('//') ? current : '/overview';
  return `/login?next=${encodeURIComponent(next)}`;
}
