import { useCallback, useEffect, useState } from 'react';
import { MenuBar } from './components/MenuBar';
import { LayoutRoot } from './components/LayoutRoot';
import { DragGhost } from './components/Panel';
import { AppModals } from './components/modals/AppModals';
import { DeviceLimitModal } from './components/modals/DeviceLimitModal';
import { ConnectionProvider, useConnection } from './context/ConnectionContext';
import { ConsoleProvider } from './context/ConsoleContext';
import { FileTreeTabProvider } from './context/FileTreeTabContext';
import { ServerDataProvider } from './context/ServerDataContext';
import { SettingsProvider, useSettings } from './context/SettingsContext';
import { useLayoutTree } from './layout/useLayoutTree';
import { workspaceBlocked } from './layout/layoutEngine';
import { isTauri, isMac, isWindows, isLinux } from './platform';

function DisconnectedNotice({ loggedIn, onOpenConnections }) {
  return (
    <div className="workspace-empty workspace-empty--disconnected" aria-label="Not connected">
      <span className="workspace-empty-label">
        {loggedIn
          ? "You don't have a project selected."
          : "You aren't logged into an organization currently."}
      </span>
      <span className="workspace-empty-hint">
        {loggedIn
          ? 'Click the globe to pick or join a project.'
          : 'Click the globe to log into your organization.'}
      </span>
      <button
        type="button"
        className="workspace-empty-action"
        onClick={onOpenConnections}
      >
        <img src="assets/globe.svg" alt="" />
        {loggedIn ? 'Open Projects' : 'Log In'}
      </button>
    </div>
  );
}

function AppShell() {
  const {
    activeWorkspace,
    setActiveWorkspace,
    layout,
    visibility,
    dragState,
    toggleVisible,
    resetWindows,
    resizeSplit,
    startDrag,
    updateDragZone,
    endDrag,
  } = useLayoutTree();
  const [activeModal, setActiveModal] = useState(null);
  const {
    projectReady,
    loggedIn,
    account,
    loginSeq,
    organizationEnabled,
    startupPending,
    workspacePath,
  } = useConnection();
  const { showTimeTracking } = useSettings();

  // Opening the app presents Login itself; the "You aren't logged in"
  // placeholder is only what's left BEHIND that modal once it's dismissed, so
  // it stays hidden until then. `startupHandled` makes the decision exactly
  // once — reopening Login every time `loggedIn` goes false would trap anyone
  // who logs out with no way back to the app.
  const [startupHandled, setStartupHandled] = useState(false);
  const [placeholderVisible, setPlaceholderVisible] = useState(false);
  const closeModal = useCallback(() => {
    setActiveModal(null);
    setPlaceholderVisible(true);
  }, []);
  useEffect(() => {
    // A remembered connection is resumed silently first (see the startup
    // effect in ConnectionContext); only once that settles is it known
    // whether a modal is needed at all. Landing logged in but without a
    // workspace folder still opens the modal — on its Projects page, exactly
    // as a typed login with nowhere to go does.
    if (startupHandled || startupPending) return;
    setStartupHandled(true);
    if (!loggedIn || !workspacePath) setActiveModal('connections');
    else setPlaceholderVisible(true);
  }, [startupHandled, startupPending, loggedIn, workspacePath]);

  // How much connection a workspace needs varies (see WORKSPACE_SCOPE):
  // Revision Control needs an active project, Administration and Organization
  // only need a session, Time Tracking is local-only. Gating all three on a
  // project is what left a project-less server with nothing but the
  // "You don't have a project selected" notice.
  const needsConnection = workspaceBlocked(activeWorkspace, { loggedIn, projectReady });

  // Administration only exists for admins/owners of the connected server —
  // logging out, or connecting somewhere you're not admin, kicks you off it.
  const isServerAdmin = loggedIn && (account?.role === 'admin' || account?.role === 'owner');
  useEffect(() => {
    if (activeWorkspace === 'administration' && !isServerAdmin) {
      setActiveWorkspace('revision');
    }
  }, [activeWorkspace, isServerAdmin, setActiveWorkspace]);

  // Time Tracking only exists while the setting is on — turning it off while
  // active bounces back to Revision Control (mirrors the Administration guard).
  useEffect(() => {
    if (activeWorkspace === 'time' && !showTimeTracking) {
      setActiveWorkspace('revision');
    }
  }, [activeWorkspace, showTimeTracking, setActiveWorkspace]);

  // Organization only exists while the connected server has it enabled —
  // losing that (or connecting elsewhere) while active bounces back too.
  useEffect(() => {
    if (activeWorkspace === 'organization' && !organizationEnabled) {
      setActiveWorkspace('revision');
    }
  }, [activeWorkspace, organizationEnabled, setActiveWorkspace]);

  const handleEdgeDown = useCallback(
    (panelId, frameEl) => {
      startDrag(panelId, frameEl);
    },
    [startDrag]
  );

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

    const onUp = () => endDrag();
    document.addEventListener('mouseup', onUp);
    return () => document.removeEventListener('mouseup', onUp);
  }, [dragState, endDrag]);

  useEffect(() => {
    // Suppress the OS/WebView's native right-click menu ("Reload", "Inspect")
    // app-wide. The custom TreeContextMenu is React-rendered from its own
    // onContextMenu handler, so it's unaffected by preventDefault here.
    const onContextMenu = (e) => e.preventDefault();
    document.addEventListener('contextmenu', onContextMenu);
    return () => document.removeEventListener('contextmenu', onContextMenu);
  }, []);

  useEffect(() => {
    // Tag the root so platform-specific chrome (macOS traffic-light drag
    // region, Windows title bar overlay, web fallback) can key off CSS.
    const root = document.documentElement;
    root.classList.toggle('is-tauri', isTauri);
    root.classList.toggle('is-web', !isTauri);
    root.classList.toggle('platform-mac', isMac);
    root.classList.toggle('platform-windows', isWindows);
    root.classList.toggle('platform-linux', isLinux);
  }, []);

  useEffect(() => {
    // macOS WKWebView (Tauri) enables native autocorrect / autocapitalize /
    // spell-suggestion on text fields; Chromium did not. Left on, it
    // "corrects" @alex -> @Alex and splits "localhost", corrupting handles, IPs,
    // and paths. Disable it app-wide on every textual input/textarea, including
    // ones mounted later (modals) via a subtree observer.
    const TEXTUAL =
      'input:not([type=checkbox]):not([type=radio]):not([type=button]):not([type=file]):not([type=range]):not([type=color]):not([type=submit]):not([type=reset]), textarea';
    const harden = (el) => {
      el.setAttribute('autocorrect', 'off');
      el.setAttribute('autocapitalize', 'off');
      el.setAttribute('spellcheck', 'false');
    };
    const scan = (node) => {
      if (node.nodeType !== 1) return;
      if (node.matches?.(TEXTUAL)) harden(node);
      node.querySelectorAll?.(TEXTUAL).forEach(harden);
    };
    scan(document.body);
    const obs = new MutationObserver((mutations) => {
      for (const m of mutations) m.addedNodes.forEach(scan);
    });
    obs.observe(document.body, { childList: true, subtree: true });
    return () => obs.disconnect();
  }, []);

  return (
    <FileTreeTabProvider
      toggleVisible={toggleVisible}
      visibility={visibility}
      loginSeq={loginSeq}
      openModal={setActiveModal}
    >
      <div id="app">
        <MenuBar
          activeWorkspace={activeWorkspace}
          onWorkspaceChange={setActiveWorkspace}
          visibility={visibility}
          onToggleVisible={toggleVisible}
          onOpenModal={setActiveModal}
        />
        <main className="layout-root">
          {needsConnection ? (
            startupPending ? (
              // The remembered connection is being redeemed. Say so rather
              // than showing an empty window for the round trip.
              <div className="workspace-empty" aria-label="Signing in">
                <span className="workspace-empty-label">Signing you in…</span>
                <span className="workspace-empty-hint">Resuming your saved sign-in.</span>
              </div>
            ) : (
              placeholderVisible && (
                <DisconnectedNotice
                  loggedIn={loggedIn}
                  onOpenConnections={() => setActiveModal('connections')}
                />
              )
            )
          ) : layout ? (
            <LayoutRoot
              layout={layout}
              dragState={dragState}
              onResize={resizeSplit}
              onEdgeDown={handleEdgeDown}
              onDropZoneHover={updateDragZone}
            />
          ) : (
            <div className="workspace-empty" aria-label="No windows">
              <span className="workspace-empty-label">Time Tracking</span>
              <span className="workspace-empty-hint">Coming soon</span>
            </div>
          )}
        </main>
        <DragGhost dragState={dragState} />
        <AppModals
          activeModal={activeModal}
          onClose={closeModal}
          onResetWindows={resetWindows}
        />
        {/* Driven by context (login device-limit), not the activeModal switch. */}
        <DeviceLimitModal />
      </div>
    </FileTreeTabProvider>
  );
}

export default function App() {
  return (
    <SettingsProvider>
      <ConnectionProvider>
        <ServerDataProvider>
          <ConsoleProvider>
            <AppShell />
          </ConsoleProvider>
        </ServerDataProvider>
      </ConnectionProvider>
    </SettingsProvider>
  );
}
