import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { request } from './api/client.js';
import { Sidebar } from './components/Sidebar.jsx';
import { ToastProvider, useToast } from './components/Toast.jsx';
import { AccountView } from './routes/AccountView.jsx';
import { AlertsView } from './routes/AlertsView.jsx';
import { AuthPanel } from './routes/AuthPanel.jsx';
import { NotificationMethodsView } from './routes/NotificationMethodsView.jsx';
import { SiteSettingsPanel } from './routes/SiteSettingsPanel.jsx';
import { SitesView } from './routes/SitesView.jsx';

const viewPaths = {
  sites: '/sites',
  alerts: '/alerts',
  notifications: '/notifications',
  account: '/account',
};

function normalizedPath(pathname) {
  if (!pathname || pathname === '/') return '/';
  return pathname.endsWith('/') ? pathname.slice(0, -1) : pathname;
}

function parseRoute(pathname) {
  const path = normalizedPath(pathname);
  if (path === '/') return { kind: 'root' };
  if (path === '/login') return { kind: 'auth', mode: 'login' };
  if (path === '/register') return { kind: 'auth', mode: 'register' };
  if (path === '/sites') return { kind: 'sites', activeView: 'sites', protected: true };
  if (path === '/alerts') return { kind: 'alerts', activeView: 'alerts', protected: true };
  if (path === '/notifications') {
    return { kind: 'notifications', activeView: 'notifications', protected: true };
  }
  if (path === '/account') return { kind: 'account', activeView: 'account', protected: true };

  const siteSettingsMatch = path.match(/^\/sites\/([^/]+)\/settings$/);
  if (siteSettingsMatch) {
    return {
      kind: 'siteSettings',
      activeView: 'sites',
      protected: true,
      siteId: decodeURIComponent(siteSettingsMatch[1]),
    };
  }

  return { kind: 'notFound' };
}

function isProtectedPath(pathname) {
  return Boolean(parseRoute(pathname).protected);
}

function currentPath() {
  return normalizedPath(window.location.pathname);
}

export function App() {
  const [user, setUser] = useState(null);
  const [locationPath, setLocationPath] = useState(currentPath);
  const [ready, setReady] = useState(false);
  const pendingReturnPath = useRef(null);

  const route = parseRoute(locationPath);

  const navigate = useCallback((path, options = {}) => {
    const nextPath = normalizedPath(path);
    if (currentPath() !== nextPath) {
      const method = options.replace ? 'replaceState' : 'pushState';
      window.history[method](null, '', nextPath);
    }
    setLocationPath(nextPath);
  }, []);

  const logout = useMemo(
    () => async () => {
      await request('/api/auth/logout', { method: 'POST' }).catch(() => {});
      pendingReturnPath.current = null;
      setUser(null);
      navigate('/login', { replace: true });
    },
    [navigate],
  );

  useEffect(() => {
    function handlePopState() {
      setLocationPath(currentPath());
    }
    window.addEventListener('popstate', handlePopState);
    return () => window.removeEventListener('popstate', handlePopState);
  }, []);

  useEffect(() => {
    async function boot() {
      const csrf = await request('/api/auth/csrf');
      localStorage.setItem('csrfToken', csrf.csrfToken);
      const me = await request('/api/auth/me').catch(() => null);
      setUser(me?.user ?? null);
      setReady(true);
    }
    boot();
  }, []);

  useEffect(() => {
    if (!ready) return;

    if (user) {
      if (route.kind === 'auth' || route.kind === 'root' || route.kind === 'notFound') {
        navigate('/sites', { replace: true });
      }
      return;
    }

    if (route.protected) {
      pendingReturnPath.current = locationPath;
      navigate('/login', { replace: true });
      return;
    }

    if (route.kind === 'root' || route.kind === 'notFound') {
      navigate('/login', { replace: true });
    }
  }, [locationPath, navigate, ready, route.kind, route.protected, user]);

  if (!ready) {
    return <div className="loading">CertRemind</div>;
  }

  if (!user) {
    const mode = route.kind === 'auth' ? route.mode : 'login';
    return (
      <AuthPanel
        mode={mode}
        onModeChange={(nextMode) => navigate(nextMode === 'register' ? '/register' : '/login')}
        onAuthed={(nextUser) => {
          setUser(nextUser);
          const returnPath = pendingReturnPath.current;
          pendingReturnPath.current = null;
          navigate(isProtectedPath(returnPath) ? returnPath : '/sites', { replace: true });
        }}
      />
    );
  }

  function withShell(content) {
    return (
      <ToastProvider>
        <div className="app-frame">
          <Sidebar
            activeView={route.activeView ?? 'sites'}
            user={user}
            onNavigate={(nextView) => navigate(viewPaths[nextView] ?? '/sites')}
            onLogout={logout}
          />
          <div className="app-content">{content}</div>
        </div>
      </ToastProvider>
    );
  }

  if (route.kind === 'siteSettings') {
    return withShell(
      <SiteSettingsRoute siteId={route.siteId} onBack={() => navigate('/sites')} navigate={navigate} />,
    );
  }

  if (route.kind === 'alerts') {
    return withShell(<AlertsView onBack={() => navigate('/sites')} />);
  }

  if (route.kind === 'notifications') {
    return withShell(<NotificationMethodsView onBack={() => navigate('/sites')} />);
  }

  if (route.kind === 'account') {
    return withShell(
      <AccountView
        onBack={() => navigate('/sites')}
        onSignedOut={() => {
          pendingReturnPath.current = null;
          setUser(null);
          navigate('/login', { replace: true });
        }}
      />,
    );
  }

  return withShell(
    <SitesView
      user={user}
      onConfigureSite={(site) =>
        navigate(`/sites/${encodeURIComponent(site.siteId)}/settings`)
      }
    />,
  );
}

function SiteSettingsRoute({ siteId, onBack, navigate }) {
  const [site, setSite] = useState(null);
  const [loadingSiteId, setLoadingSiteId] = useState(siteId);
  const { showToast } = useToast();

  useEffect(() => {
    let active = true;
    setSite(null);
    setLoadingSiteId(siteId);

    async function loadSite() {
      try {
        const data = await request(`/api/sites/${siteId}`);
        if (active) {
          setSite(data.site);
        }
      } catch (err) {
        if (active) {
          showToast({ type: 'error', message: err.message });
          navigate('/sites', { replace: true });
        }
      }
    }

    loadSite();
    return () => {
      active = false;
    };
  }, [navigate, showToast, siteId]);

  if (!site || loadingSiteId !== siteId) {
    return <div className="loading">CertRemind</div>;
  }

  return <SiteSettingsPanel site={site} onBack={onBack} />;
}
