import React, { DragEvent, useEffect, useMemo, useRef, useState } from "react";
import { createRoot } from "react-dom/client";
import {
  Download,
  ExternalLink,
  FileText,
  Image as ImageIcon,
  Layers,
  LayoutTemplate,
  Loader2,
  Palette,
  Paperclip,
  Pencil,
  Save,
  Upload,
  WandSparkles,
  X
} from "lucide-react";
import "./styles.css";

type Mode = "template-build" | "deck-build" | "template-edit" | "deck-edit";

type DeckResult = {
  id: string;
  title: string;
  slides: number;
  specUrl: string;
  pptxUrl: string;
  source?: {
    title?: string;
    type?: string;
    sourceName?: string;
  };
};

type DesignTemplate = {
  id: string;
  name: string;
  description: string;
  sourceName?: string;
  colors: string[];
  updatedAt: string;
  locked?: boolean;
};

const initialContent = `# Customer Discovery Notes

Paste notes, transcript excerpts, or brief content here.

- Confirm the top decisions.
- Build an executive narrative.
- Render a PPTX for review.`;

const starterTemplate: DesignTemplate = {
  id: "incorta",
  name: "Incorta Starter",
  description:
    "White executive deck, orange brand accent, restrained blue secondary accents, Aptos typography, compact business density, fixed title/body/two-column/roadmap layouts.",
  colors: ["#ffffff", "#f05a28", "#1e6bff", "#172033", "#596579"],
  updatedAt: "2026-06-09T00:00:00.000Z",
  locked: true
};

const modeTabs: Array<{ id: Mode; label: string; icon: React.ElementType }> = [
  { id: "template-build", label: "Build Template", icon: LayoutTemplate },
  { id: "deck-build", label: "Build Slide / Deck", icon: Layers },
  { id: "template-edit", label: "Edit Template", icon: Palette },
  { id: "deck-edit", label: "Edit Slide / Deck", icon: Pencil }
];

function App() {
  const [activeMode, setActiveMode] = useState<Mode>("template-build");
  const [templates, setTemplates] = useState<DesignTemplate[]>([starterTemplate]);
  const [selectedTemplateId, setSelectedTemplateId] = useState(starterTemplate.id);

  const [content, setContent] = useState(initialContent);
  const [instructions, setInstructions] = useState("Create a concise executive deck.");
  const [file, setFile] = useState<File | null>(null);
  const [previewUrl, setPreviewUrl] = useState<string | null>(null);
  const [dragging, setDragging] = useState(false);

  const [templateName, setTemplateName] = useState("New design standard");
  const [templateDescription, setTemplateDescription] = useState(
    "Executive presentation system with clear hierarchy, reusable slide sections, consistent spacing, and restrained visual emphasis."
  );
  const [templateFile, setTemplateFile] = useState<File | null>(null);
  const [templatePreviewUrl, setTemplatePreviewUrl] = useState<string | null>(null);
  const [templateDragging, setTemplateDragging] = useState(false);
  const [editTemplateId, setEditTemplateId] = useState(starterTemplate.id);
  const [editTemplateName, setEditTemplateName] = useState(starterTemplate.name);
  const [editTemplateDescription, setEditTemplateDescription] = useState(starterTemplate.description);

  const [result, setResult] = useState<DeckResult | null>(null);
  const [notice, setNotice] = useState<string | null>(null);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const fileInputRef = useRef<HTMLInputElement>(null);
  const templateInputRef = useRef<HTMLInputElement>(null);

  useEffect(() => {
    try {
      const stored = window.localStorage.getItem("slideFactory.designTemplates.v1");
      if (!stored) return;
      const parsed = JSON.parse(stored) as DesignTemplate[];
      const customTemplates = parsed.filter((template) => template.id !== starterTemplate.id);
      setTemplates([starterTemplate, ...customTemplates]);
    } catch {
      setTemplates([starterTemplate]);
    }
  }, []);

  useEffect(() => {
    const customTemplates = templates.filter((template) => !template.locked);
    window.localStorage.setItem("slideFactory.designTemplates.v1", JSON.stringify(customTemplates));
  }, [templates]);

  const selectedTemplate = useMemo(
    () => templates.find((template) => template.id === selectedTemplateId) || starterTemplate,
    [selectedTemplateId, templates]
  );

  const editableTemplate = useMemo(
    () => templates.find((template) => template.id === editTemplateId) || starterTemplate,
    [editTemplateId, templates]
  );

  const activeTemplatePreview = useMemo<DesignTemplate>(() => {
    if (activeMode === "template-build") {
      return {
        id: "draft-template",
        name: templateName.trim() || "Untitled design standard",
        description: templateDescription.trim(),
        sourceName: templateFile?.name,
        colors: starterTemplate.colors,
        updatedAt: new Date().toISOString()
      };
    }

    if (activeMode === "template-edit") {
      return {
        ...editableTemplate,
        name: editTemplateName.trim() || editableTemplate.name,
        description: editTemplateDescription.trim()
      };
    }

    return selectedTemplate;
  }, [
    activeMode,
    editableTemplate,
    editTemplateDescription,
    editTemplateName,
    selectedTemplate,
    templateDescription,
    templateFile,
    templateName
  ]);

  const sourceLabel = useMemo(() => {
    if (file) return `${file.name} · ${formatBytes(file.size)}`;
    const chars = content.trim().length;
    return chars ? `${chars.toLocaleString()} characters pasted` : "No source selected";
  }, [content, file]);

  const templateSourceLabel = useMemo(() => {
    if (templateFile) return `${templateFile.name} · ${formatBytes(templateFile.size)}`;
    return "No design source selected";
  }, [templateFile]);

  function setSourceFile(nextFile: File | null) {
    if (previewUrl) URL.revokeObjectURL(previewUrl);
    setFile(nextFile);
    setResult(null);
    setError(null);
    if (nextFile?.type.startsWith("image/")) {
      setPreviewUrl(URL.createObjectURL(nextFile));
    } else {
      setPreviewUrl(null);
    }
  }

  function setTemplateSourceFile(nextFile: File | null) {
    if (templatePreviewUrl) URL.revokeObjectURL(templatePreviewUrl);
    setTemplateFile(nextFile);
    setNotice(null);
    setError(null);
    if (nextFile?.type.startsWith("image/")) {
      setTemplatePreviewUrl(URL.createObjectURL(nextFile));
    } else {
      setTemplatePreviewUrl(null);
    }
  }

  function onSourceDrop(event: DragEvent<HTMLLabelElement>) {
    event.preventDefault();
    setDragging(false);
    const dropped = event.dataTransfer.files?.[0];
    if (dropped) setSourceFile(dropped);
  }

  function onTemplateDrop(event: DragEvent<HTMLLabelElement>) {
    event.preventDefault();
    setTemplateDragging(false);
    const dropped = event.dataTransfer.files?.[0];
    if (dropped) setTemplateSourceFile(dropped);
  }

  async function onPaste(event: React.ClipboardEvent<HTMLTextAreaElement>) {
    const image = Array.from(event.clipboardData.files).find((item) => item.type.startsWith("image/"));
    if (image) {
      event.preventDefault();
      setSourceFile(image);
    }
  }

  function saveTemplate() {
    const name = templateName.trim() || "Untitled design standard";
    const template: DesignTemplate = {
      id: `template-${Date.now()}`,
      name,
      description: templateDescription.trim(),
      sourceName: templateFile?.name,
      colors: starterTemplate.colors,
      updatedAt: new Date().toISOString()
    };
    setTemplates((current) => [starterTemplate, template, ...current.filter((item) => item.id !== starterTemplate.id)]);
    setSelectedTemplateId(template.id);
    setEditTemplateId(template.id);
    setEditTemplateName(template.name);
    setEditTemplateDescription(template.description);
    setNotice(`${template.name} saved`);
  }

  function loadEditableTemplate(templateId: string) {
    const template = templates.find((item) => item.id === templateId) || starterTemplate;
    setEditTemplateId(template.id);
    setEditTemplateName(template.name);
    setEditTemplateDescription(template.description);
    setNotice(null);
    setError(null);
  }

  function updateTemplate() {
    if (editableTemplate.locked) {
      const copy: DesignTemplate = {
        ...editableTemplate,
        id: `template-${Date.now()}`,
        name: `${editTemplateName.trim() || editableTemplate.name} Copy`,
        description: editTemplateDescription.trim(),
        locked: false,
        updatedAt: new Date().toISOString()
      };
      setTemplates((current) => [starterTemplate, copy, ...current.filter((item) => item.id !== starterTemplate.id)]);
      setSelectedTemplateId(copy.id);
      setEditTemplateId(copy.id);
      setEditTemplateName(copy.name);
      setNotice(`${copy.name} saved`);
      return;
    }

    setTemplates((current) =>
      current.map((template) =>
        template.id === editTemplateId
          ? {
              ...template,
              name: editTemplateName.trim() || template.name,
              description: editTemplateDescription.trim(),
              updatedAt: new Date().toISOString()
            }
          : template
      )
    );
    setNotice(`${editTemplateName.trim() || editableTemplate.name} updated`);
  }

  function removeEditableTemplate() {
    if (editableTemplate.locked) return;
    setTemplates((current) => current.filter((template) => template.id !== editableTemplate.id));
    setSelectedTemplateId(starterTemplate.id);
    loadEditableTemplate(starterTemplate.id);
    setNotice(`${editableTemplate.name} removed`);
  }

  async function createDeck() {
    setBusy(true);
    setError(null);
    setNotice(null);
    setResult(null);
    try {
      const response = file ? await createDeckFromFile(file) : await createDeckFromText();
      const json = await response.json();
      if (!response.ok) throw new Error(json.error || "Deck generation failed");
      setResult(json);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Unknown error");
    } finally {
      setBusy(false);
    }
  }

  function designAwareInstructions() {
    return [
      instructions,
      "",
      `Selected design template: ${selectedTemplate.name}.`,
      selectedTemplate.description
    ]
      .filter(Boolean)
      .join("\n");
  }

  function createDeckFromFile(sourceFile: File) {
    const formData = new FormData();
    formData.set("source", sourceFile);
    formData.set("style", "incorta");
    formData.set("audience", "executives");
    formData.set("instructions", designAwareInstructions());
    return fetch("/api/decks/from-source", {
      method: "POST",
      body: formData
    });
  }

  function createDeckFromText() {
    return fetch("/api/decks", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        style: "incorta",
        instructions: designAwareInstructions(),
        input: { type: "markdown", content }
      })
    });
  }

  const title = modeTabs.find((mode) => mode.id === activeMode)?.label || "Slide Factory";

  return (
    <main className="app-shell">
      <section className="workspace">
        <header className="topbar">
          <div>
            <p className="eyebrow">Slide Factory</p>
            <h1>{title}</h1>
          </div>
          <div className="topbar-actions">
            <a className="secondary-action" href="/google-slides-workflow.html">
              <ExternalLink size={16} />
              Google Slides workflow
            </a>
            {activeMode === "template-build" && (
              <button className="primary-action" onClick={saveTemplate}>
                <Save size={18} />
                Save template
              </button>
            )}
            {activeMode === "deck-build" && (
              <button className="primary-action" onClick={createDeck} disabled={busy}>
                {busy ? <Loader2 className="spin" size={18} /> : <WandSparkles size={18} />}
                {busy ? "Building" : "Build deck"}
              </button>
            )}
            {activeMode === "template-edit" && (
              <button className="primary-action" onClick={updateTemplate}>
                <Save size={18} />
                Save edits
              </button>
            )}
            {activeMode === "deck-edit" && (
              <button className="primary-action" onClick={createDeck} disabled={busy}>
                {busy ? <Loader2 className="spin" size={18} /> : <WandSparkles size={18} />}
                {busy ? "Rebuilding" : "Build revision"}
              </button>
            )}
          </div>
        </header>

        <nav className="mode-tabs" aria-label="Slide Factory modes">
          {modeTabs.map((mode) => {
            const Icon = mode.icon;
            return (
              <button
                key={mode.id}
                type="button"
                className={`mode-tab ${activeMode === mode.id ? "is-active" : ""}`}
                onClick={() => setActiveMode(mode.id)}
              >
                <Icon size={16} />
                {mode.label}
              </button>
            );
          })}
        </nav>

        <div className="main-grid">
          <section className="source-pane">
            {activeMode === "template-build" && (
              <TemplateBuildPane
                dragging={templateDragging}
                inputRef={templateInputRef}
                name={templateName}
                previewUrl={templatePreviewUrl}
                sourceLabel={templateSourceLabel}
                description={templateDescription}
                onDrop={onTemplateDrop}
                onDragging={setTemplateDragging}
                onFile={setTemplateSourceFile}
                onName={setTemplateName}
                onDescription={setTemplateDescription}
                onSave={saveTemplate}
              />
            )}

            {activeMode === "deck-build" && (
              <DeckBuildPane
                content={content}
                dragging={dragging}
                file={file}
                fileInputRef={fileInputRef}
                instructions={instructions}
                previewUrl={previewUrl}
                selectedTemplateId={selectedTemplateId}
                sourceLabel={sourceLabel}
                templates={templates}
                onContent={setContent}
                onDragging={setDragging}
                onDrop={onSourceDrop}
                onFile={setSourceFile}
                onInstructions={setInstructions}
                onPaste={onPaste}
                onTemplate={setSelectedTemplateId}
              />
            )}

            {activeMode === "template-edit" && (
              <TemplateEditPane
                description={editTemplateDescription}
                editableTemplate={editableTemplate}
                name={editTemplateName}
                templateId={editTemplateId}
                templates={templates}
                onDescription={setEditTemplateDescription}
                onName={setEditTemplateName}
                onRemove={removeEditableTemplate}
                onTemplate={loadEditableTemplate}
              />
            )}

            {activeMode === "deck-edit" && (
              <DeckEditPane
                content={content}
                dragging={dragging}
                file={file}
                fileInputRef={fileInputRef}
                instructions={instructions}
                previewUrl={previewUrl}
                selectedTemplateId={selectedTemplateId}
                sourceLabel={sourceLabel}
                templates={templates}
                onContent={setContent}
                onDragging={setDragging}
                onDrop={onSourceDrop}
                onFile={setSourceFile}
                onInstructions={setInstructions}
                onPaste={onPaste}
                onTemplate={setSelectedTemplateId}
              />
            )}
          </section>

          <OutputPanel
            activeMode={activeMode}
            error={error}
            notice={notice}
            result={result}
            template={activeTemplatePreview}
            templates={templates}
          />
        </div>
      </section>
    </main>
  );
}

function TemplateBuildPane(props: {
  dragging: boolean;
  inputRef: React.RefObject<HTMLInputElement>;
  name: string;
  previewUrl: string | null;
  sourceLabel: string;
  description: string;
  onDrop: (event: DragEvent<HTMLLabelElement>) => void;
  onDragging: (dragging: boolean) => void;
  onFile: (file: File | null) => void;
  onName: (value: string) => void;
  onDescription: (value: string) => void;
  onSave: () => void;
}) {
  return (
    <>
      <label
        className={`drop-zone ${props.dragging ? "is-dragging" : ""}`}
        onDragOver={(event) => {
          event.preventDefault();
          props.onDragging(true);
        }}
        onDragLeave={() => props.onDragging(false)}
        onDrop={props.onDrop}
      >
        <input
          ref={props.inputRef}
          type="file"
          accept=".ppt,.pptx,.pdf,image/*"
          onChange={(event) => props.onFile(event.target.files?.[0] || null)}
        />
        <Upload size={20} />
        <span>Drop design source</span>
        <button type="button" className="secondary-action" onClick={() => props.inputRef.current?.click()}>
          <Paperclip size={16} />
          Choose file
        </button>
      </label>

      <div className="source-status">
        <span>{props.sourceLabel}</span>
        {props.previewUrl && (
          <button type="button" className="icon-action" onClick={() => props.onFile(null)} aria-label="Clear design source">
            <X size={16} />
          </button>
        )}
      </div>

      {props.previewUrl && (
        <div className="image-preview">
          <img src={props.previewUrl} alt="" />
        </div>
      )}

      <label className="field">
        <span>Template name</span>
        <input value={props.name} onChange={(event) => props.onName(event.target.value)} />
      </label>

      <label className="field content compact">
        <span>Design description</span>
        <textarea value={props.description} onChange={(event) => props.onDescription(event.target.value)} />
      </label>

      <button type="button" className="secondary-action wide-action" onClick={props.onSave}>
        <Save size={16} />
        Save template
      </button>
    </>
  );
}

function DeckBuildPane(props: DeckPaneProps) {
  return (
    <>
      <TemplateSelect templates={props.templates} value={props.selectedTemplateId} onChange={props.onTemplate} />
      <SourceInput {...props} dropLabel="Drop source" textLabel="Paste source" />
    </>
  );
}

function DeckEditPane(props: DeckPaneProps) {
  return (
    <>
      <TemplateSelect templates={props.templates} value={props.selectedTemplateId} onChange={props.onTemplate} />
      <SourceInput {...props} dropLabel="Drop slide / deck" textLabel="Revision notes" />
    </>
  );
}

type DeckPaneProps = {
  content: string;
  dragging: boolean;
  file: File | null;
  fileInputRef: React.RefObject<HTMLInputElement>;
  instructions: string;
  previewUrl: string | null;
  selectedTemplateId: string;
  sourceLabel: string;
  templates: DesignTemplate[];
  onContent: (value: string) => void;
  onDragging: (dragging: boolean) => void;
  onDrop: (event: DragEvent<HTMLLabelElement>) => void;
  onFile: (file: File | null) => void;
  onInstructions: (value: string) => void;
  onPaste: (event: React.ClipboardEvent<HTMLTextAreaElement>) => void;
  onTemplate: (id: string) => void;
};

function TemplateSelect(props: { templates: DesignTemplate[]; value: string; onChange: (id: string) => void }) {
  const active = props.templates.find((template) => template.id === props.value) || starterTemplate;
  return (
    <div className="template-select">
      <label className="field">
        <span>Design template</span>
        <select value={props.value} onChange={(event) => props.onChange(event.target.value)}>
          {props.templates.map((template) => (
            <option key={template.id} value={template.id}>
              {template.name}
            </option>
          ))}
        </select>
      </label>
      <Swatches colors={active.colors} />
    </div>
  );
}

function SourceInput(props: DeckPaneProps & { dropLabel: string; textLabel: string }) {
  return (
    <>
      <label
        className={`drop-zone ${props.dragging ? "is-dragging" : ""}`}
        onDragOver={(event) => {
          event.preventDefault();
          props.onDragging(true);
        }}
        onDragLeave={() => props.onDragging(false)}
        onDrop={props.onDrop}
      >
        <input
          ref={props.fileInputRef}
          type="file"
          accept=".md,.markdown,.txt,.pdf,.ppt,.pptx,image/*"
          onChange={(event) => props.onFile(event.target.files?.[0] || null)}
        />
        <Upload size={20} />
        <span>{props.dropLabel}</span>
        <button type="button" className="secondary-action" onClick={() => props.fileInputRef.current?.click()}>
          <Paperclip size={16} />
          Choose file
        </button>
      </label>

      <div className="source-status">
        <span>{props.sourceLabel}</span>
        {props.file && (
          <button type="button" className="icon-action" onClick={() => props.onFile(null)} aria-label="Clear file">
            <X size={16} />
          </button>
        )}
      </div>

      {props.previewUrl && (
        <div className="image-preview">
          <img src={props.previewUrl} alt="" />
        </div>
      )}

      <label className="field">
        <span>Instructions</span>
        <input value={props.instructions} onChange={(event) => props.onInstructions(event.target.value)} />
      </label>

      <label className="field content">
        <span>{props.textLabel}</span>
        <textarea
          value={props.content}
          onPaste={props.onPaste}
          onChange={(event) => {
            props.onContent(event.target.value);
            if (props.file) props.onFile(null);
          }}
        />
      </label>
    </>
  );
}

function TemplateEditPane(props: {
  description: string;
  editableTemplate: DesignTemplate;
  name: string;
  templateId: string;
  templates: DesignTemplate[];
  onDescription: (value: string) => void;
  onName: (value: string) => void;
  onRemove: () => void;
  onTemplate: (id: string) => void;
}) {
  return (
    <>
      <div className="template-select">
        <label className="field">
          <span>Template</span>
          <select value={props.templateId} onChange={(event) => props.onTemplate(event.target.value)}>
            {props.templates.map((template) => (
              <option key={template.id} value={template.id}>
                {template.name}
              </option>
            ))}
          </select>
        </label>
        <Swatches colors={props.editableTemplate.colors} />
      </div>

      <label className="field">
        <span>Template name</span>
        <input value={props.name} onChange={(event) => props.onName(event.target.value)} />
      </label>

      <label className="field content compact">
        <span>Design description</span>
        <textarea value={props.description} onChange={(event) => props.onDescription(event.target.value)} />
      </label>

      <div className="button-row">
        <button type="button" className="secondary-action" onClick={props.onRemove} disabled={props.editableTemplate.locked}>
          <X size={16} />
          Remove
        </button>
      </div>
    </>
  );
}

function OutputPanel(props: {
  activeMode: Mode;
  error: string | null;
  notice: string | null;
  result: DeckResult | null;
  template: DesignTemplate;
  templates: DesignTemplate[];
}) {
  const templateMode = props.activeMode === "template-build" || props.activeMode === "template-edit";
  return (
    <aside className="result-panel">
      <div className="result-title">
        {templateMode ? <LayoutTemplate size={18} /> : <FileText size={18} />}
        <span>{templateMode ? "Template" : "Output"}</span>
      </div>

      {props.error && <p className="error">{props.error}</p>}
      {props.notice && <p className="notice">{props.notice}</p>}

      {templateMode ? (
        <div className="result">
          <strong>{props.template.name}</strong>
          <Swatches colors={props.template.colors} />
          {props.template.description && <p className="template-summary">{props.template.description}</p>}
          <span>{props.templates.length} templates</span>
          {props.template.sourceName && <span className="source-chip">{props.template.sourceName}</span>}
        </div>
      ) : (
        <>
          {!props.result && !props.error && <p className="muted">Ready for a source.</p>}
          {props.result && (
            <div className="result">
              <strong>{props.result.title}</strong>
              <span>{props.result.slides} slides</span>
              {props.result.source?.sourceName && <span className="source-chip">{props.result.source.sourceName}</span>}
              <a href={props.result.pptxUrl}>
                <Download size={16} />
                PPTX
              </a>
              <a href={props.result.specUrl}>DeckSpec JSON</a>
            </div>
          )}
        </>
      )}
    </aside>
  );
}

function Swatches(props: { colors: string[] }) {
  return (
    <div className="swatches" aria-label="Template colors">
      {props.colors.map((color) => (
        <span key={color} className="swatch" style={{ background: color }} />
      ))}
    </div>
  );
}

function formatBytes(value: number) {
  if (value < 1024) return `${value} B`;
  if (value < 1024 * 1024) return `${Math.round(value / 1024)} KB`;
  return `${(value / 1024 / 1024).toFixed(1)} MB`;
}

createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
