import { useEffect, useRef } from 'react';
import { ConfirmDialog } from './components/ConfirmDialog';
import { LivePreview } from './components/LivePreview';
import { ModalShell } from './components/ModalShell';
import { PaneToggleStrip } from './components/PaneToggleStrip';
import { ResizeHandle } from './components/ResizeHandle';
import { SnippetLibrary } from './components/SnippetLibrary';
import { SpecEditor } from './components/SpecEditor';
import { ThemeToggle } from './components/ThemeToggle';
import { Toaster } from './components/Toaster';
import { openModal, setConfirm } from './modals/ModalCoordinator';
import { confirm } from './stores/ConfirmStore';
import { usePanesStore } from './stores/PanesStore';
import { exportWorkspace, importWorkspace } from './services/transfer';
import styles from './App.module.css';

/**
 * Application shell — the three-pane workspace from spec §01A
 * (library · editor · preview) under a fixed header.
 *
 * The center editor flexes; the library and preview carry remembered widths and
 * are resized via the drag handles between them (spec §01A). Each pane can be
 * shown/hidden from the always-present toggle strip (the leftmost rail); a hidden
 * pane frees its space and the rest redistribute — when the editor is hidden the
 * two side panes flex proportionally to their remembered widths.
 */
export function App() {
  const libraryWidth = usePanesStore((s) => s.libraryWidth);
  const previewWidth = usePanesStore((s) => s.previewWidth);
  const libraryVisible = usePanesStore((s) => s.libraryVisible);
  const editorVisible = usePanesStore((s) => s.editorVisible);
  const previewVisible = usePanesStore((s) => s.previewVisible);

  // Side-pane sizing: fixed remembered width while the editor (the flex filler) is
  // present; when it's hidden, the side panes grow proportionally to those widths
  // so they fill the freed space (spec §01A → "redistributing proportionally").
  const sideStyle = (width: number): React.CSSProperties =>
    editorVisible ? { width } : { flex: `${width} 1 0` };
  // Hidden file input driving Import — the header button proxies its click so the
  // browser file picker is the only chrome (spec §08 → no intermediate dialog).
  const fileInputRef = useRef<HTMLInputElement>(null);

  // Route the modal coordinator's discard prompt through the in-app confirm
  // dialog (docs/architecture/03 → "The coordinator seam").
  useEffect(() => {
    setConfirm((message) => confirm({ title: 'Discard changes?', message, danger: true }));
  }, []);

  const handleImportFile = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    // Reset the input so picking the same file again still fires onChange.
    e.target.value = '';
    if (file) void importWorkspace(file);
  };

  return (
    <div className={styles.app}>
      {/* Skip link (WCAG 2.4.1 / GOV.UK): the first focusable element, hidden
          until focused, lets keyboard users bypass the header into the work area. */}
      <a className={styles.skipLink} href="#main">
        Skip to content
      </a>
      <header className={styles.header}>
        <h1 className={styles.title}>Astrolabe</h1>
        <span className={styles.version}>v{__APP_VERSION__}</span>
        <span className={styles.spacer} />
        <button
          type="button"
          className={styles.headerButton}
          onClick={() => openModal('datasets')}
          aria-keyshortcuts="Meta+K Control+K"
          title="Datasets (⌘/Ctrl+K)"
        >
          Datasets
        </button>
        <button
          type="button"
          className={styles.headerButton}
          onClick={() => fileInputRef.current?.click()}
          title="Import a workspace JSON file"
        >
          Import
        </button>
        <button
          type="button"
          className={styles.headerButton}
          onClick={() => exportWorkspace()}
          title="Export your workspace to a JSON file"
        >
          Export
        </button>
        <button
          type="button"
          className={styles.headerButton}
          onClick={() => openModal('about')}
          title="About, keyboard shortcuts, and privacy information"
        >
          About &amp; Privacy
        </button>
        <button
          type="button"
          className={styles.headerButton}
          onClick={() => openModal('donate')}
          title="Support Astrolabe"
        >
          Donate
        </button>
        <ThemeToggle />
        {/* Hidden picker for Import; restricted to JSON (spec §08). */}
        <input
          ref={fileInputRef}
          type="file"
          accept="application/json,.json"
          className={styles.hiddenInput}
          onChange={handleImportFile}
          aria-hidden="true"
          tabIndex={-1}
        />
      </header>

      {/* tabIndex -1 makes the landmark a focus target for the skip link. */}
      <main id="main" className={styles.panes} tabIndex={-1}>
        {/* Always-present rail: shows/hides panes and shortcuts to Datasets (§01A). */}
        <PaneToggleStrip />
        {libraryVisible && (
          <section
            id="pane-library"
            className={styles.pane}
            style={sideStyle(libraryWidth)}
            aria-label="Snippet library"
          >
            <SnippetLibrary />
          </section>
        )}
        {/* A resize handle only sits between two visible panes that flank the editor. */}
        {libraryVisible && editorVisible && (
          <ResizeHandle side="library" label="Resize snippet library" />
        )}
        {editorVisible && (
          <section id="pane-editor" className={styles.paneEditor} aria-label="Spec editor">
            <SpecEditor />
          </section>
        )}
        {editorVisible && previewVisible && (
          <ResizeHandle side="preview" label="Resize live preview" />
        )}
        {previewVisible && (
          <section
            id="pane-preview"
            className={styles.pane}
            style={sideStyle(previewWidth)}
            aria-label="Live preview"
          >
            <LivePreview />
          </section>
        )}
      </main>

      {/* The one feature modal (Datasets / Extract / …), rendered from the
          registry by the shared shell. At most one open at a time (spec §01C). */}
      <ModalShell />

      {/* Global confirmation layer — sits above the feature-modal shell so a
          discard-changes prompt can appear over an open modal. */}
      <ConfirmDialog />

      {/* Non-blocking notifications (failed saves, etc.) — top-right toasts,
          layered above the confirm backdrop so a failure stays visible. */}
      <Toaster />
    </div>
  );
}
