// The dual-canvas workspace shell.
// Composes TopBar / SocratesDock / LeftRail / TextCanvas / DiagramCanvas / StatusBar.
// M4 adds: SysML model derivation + validation, IssuesPanel, optional ?break=...
// query param to demonstrate the validator surfacing rule violations.

"use client";

import { useMemo, useState } from "react";
import { useSearchParams } from "next/navigation";
import { TopBar } from "./TopBar";
import { LeftRail } from "./LeftRail";
import { CanvasHeader } from "./CanvasHeader";
import { StatusBar } from "./StatusBar";
import { IssuesPanel } from "./IssuesPanel";
import { TextCanvas } from "../text-canvas/TextCanvas";
import { DiagramCanvas, type DiagramVariant } from "../diagram-canvas/DiagramCanvas";
import { SocratesDock, type Density, type SocratesPresence } from "../socrates/SocratesDock";
import type { MarkupStyle } from "../text-canvas/Chip";
import type { FixtureData } from "../../lib/fixtures/aristotle";
import { fromFixture } from "../../lib/sysml/fromFixture";
import { validate, type ValidationIssue } from "../../lib/sysml/validate";
import { applyBreaks, BREAKS, type BreakName } from "../../lib/sysml/breaks";

interface EditorShellProps {
  data: FixtureData;
  density?: Density;
  markupStyle?: MarkupStyle;
  diagramStyle?: DiagramVariant;
  presence?: SocratesPresence;
}

export function EditorShell({
  data,
  density = "comfortable",
  markupStyle = "color",
  diagramStyle = "softened",
  presence = "default",
}: EditorShellProps) {
  const [focusBlockId, setFocusBlockId] = useState<string | null>(null);
  const searchParams = useSearchParams();

  // Parse `?break=S1-dangling,M2-cycle&...` into a list of named corruptions.
  const breaks = useMemo<BreakName[]>(() => {
    const raw = searchParams?.get("break") ?? "";
    if (!raw) return [];
    return raw
      .split(",")
      .map(s => s.trim())
      .filter((s): s is BreakName => s in BREAKS);
  }, [searchParams]);

  // Derive the SysML model from the fixture, optionally apply breaks, validate.
  const { issues, issuesByElement } = useMemo(() => {
    const baseModel = fromFixture(data);
    const broken = breaks.length > 0 ? applyBreaks(baseModel, breaks) : baseModel;
    const issues = validate(broken);
    const issuesByElement = new Map<string, ValidationIssue[]>();
    for (const i of issues) {
      const key = anchorKey(i.anchor);
      if (!key) continue;
      const prev = issuesByElement.get(key) ?? [];
      prev.push(i);
      issuesByElement.set(key, prev);
    }
    return { issues, issuesByElement };
  }, [data, breaks]);

  return (
    <div className={`shell shell-density-${density} shell-presence-${presence}`}>
      <TopBar data={data} />

      <div className="shell-body">
        <SocratesDock thread={data.socratesThread} presence={presence} density={density} />
        <LeftRail
          data={data}
          focusBlockId={focusBlockId}
          setFocusBlockId={setFocusBlockId}
          issuesByElement={issuesByElement}
        />

        <main className="canvases">
          <section className="canvas canvas-text">
            <CanvasHeader title="Narrative" subtitle="Markup-augmented prose · synced to model" />
            <div className="canvas-scroll">
              <TextCanvas
                data={data}
                density={density}
                markupStyle={markupStyle}
                focusBlockId={focusBlockId}
                setFocusBlockId={setFocusBlockId}
              />
            </div>
          </section>

          <div className="canvas-divider" />

          <section className="canvas canvas-diagram">
            <CanvasHeader
              title="Model"
              subtitle={breaks.length > 0
                ? `SysML · breaks active: ${breaks.join(", ")}`
                : "SysML · 6 blocks · 6 associations · 1 constraint"}
              right={
                <div className="canvas-actions">
                  <span className="canvas-mode-pill">Fit</span>
                  <span className="canvas-mode-pill canvas-mode-active">100%</span>
                  <span className="canvas-mode-pill">Layout</span>
                </div>
              }
            />
            <div className="canvas-scroll canvas-scroll-diagram">
              <DiagramCanvas
                data={data}
                density={density}
                variant={diagramStyle}
                focusBlockId={focusBlockId}
                onSelect={setFocusBlockId}
                issuesByElement={issuesByElement}
              />
            </div>
          </section>
        </main>
      </div>

      <StatusBar data={data} />

      <IssuesPanel issues={issues} onSelectAnchor={id => setFocusBlockId(id)} />
    </div>
  );
}

/** Map an issue's anchor to a single string key matching either a block id or
 * a synthetic key (`assoc:a1`, `req:req-001`, `constraint:ferpa`). The UI uses
 * block ids most often, so block anchors return the bare id. */
function anchorKey(anchor: ValidationIssue["anchor"]): string | null {
  switch (anchor.kind) {
    case "block": return anchor.id;
    case "association": return `assoc:${anchor.id}`;
    case "constraint": return `constraint:${anchor.id}`;
    case "requirement": return `req:${anchor.id}`;
    case "property": return anchor.blockId;
    case "model": return null;
  }
}
