import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import Chatbot from "./chatbot.jsx";

const VFS_ORIGIN = "https://vfs.local";

function normalizeFilePath(path) {
  if (!path) return "/app.jsx";
  if (path.startsWith(VFS_ORIGIN)) {
    try {
      const url = new URL(path);
      return url.pathname || "/app.jsx";
    } catch {
      return "/app.jsx";
    }
  }
  const withLeadingSlash = path.startsWith("/") ? path : `/${path}`;
  return withLeadingSlash.replace(/\\/g, "/");
}

function safeJsonForInlineScript(value) {
  // Prevent accidental </script> termination.
  return JSON.stringify(value).replace(/<\/script/gi, "<\\/script");
}

function guessContentType(pathname) {
  if (pathname.endsWith(".css")) return "text/css";
  if (pathname.endsWith(".html")) return "text/html";
  if (pathname.endsWith(".json")) return "application/json";
  return "application/javascript";
}

function buildIframeSrcDoc(project) {
  const entryPath = normalizeFilePath(project?.entry || "/app.jsx");
  const files = project?.files || {};
  const normalizedFiles = {};
  for (const [key, value] of Object.entries(files)) {
    const path = normalizeFilePath(key);
    normalizedFiles[path] = String(value ?? "");
  }

  // Ensure entry exists (otherwise Bundless will fetch 404 and you'll get nothing).
  if (!normalizedFiles[entryPath]) {
    normalizedFiles[entryPath] = `import React from "react";\nimport ReactDOM from "react-dom";\n\nfunction App(){\n  return <div style={{fontFamily: 'sans-serif', padding: 12}}>No entry file found: ${entryPath}</div>;\n}\n\nReactDOM.render(<App />, document.getElementById('react-root'));\n`;
  }

  const vfsJson = safeJsonForInlineScript({
    origin: VFS_ORIGIN,
    entry: entryPath,
    files: normalizedFiles,
  });

  // Note: srcdoc inherits base URL of parent, so /bundless.sucrase.min.js resolves.
  return `<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Preview</title>
    <script type="importmap">
      {
        "imports": {
          "react": "https://cdn.skypack.dev/-/react@v17.0.1-yH0aYV1FOvoIPeKBbHxg/dist=es2019,mode=imports/optimized/react.js",
          "react-dom": "https://cdn.skypack.dev/-/react-dom@v17.0.1-oZ1BXZ5opQ1DbTh7nu9r/dist=es2019,mode=imports/optimized/react-dom.js"
        }
      }
    </script>
    <style>
      html, body { margin: 0; padding: 0; }
    </style>
  </head>
  <body>
    <div id="react-root"></div>
    <script>
      window.__VFS__ = ${vfsJson};
      (function installVfsFetch(){
        const vfs = window.__VFS__;
        const realFetch = window.fetch.bind(window);
        window.fetch = async (input, init) => {
          try {
            const rawUrl = typeof input === 'string' ? input : input && input.url;
            if (!rawUrl) {
              return realFetch(input, init);
            }
            const url = new URL(rawUrl, window.location.href);
            const pathname = url.pathname;
            const hasVirtualFile = Object.prototype.hasOwnProperty.call(vfs.files, pathname);
            const isVirtualOrigin = url.origin === vfs.origin;

            // Serve either explicit vfs.local requests or root-relative requests that
            // map to virtual files (e.g. "/components/Button.jsx").
            if (isVirtualOrigin || hasVirtualFile) {
              if (hasVirtualFile) {
                const body = vfs.files[pathname];
                const headers = new Headers({ "Content-Type": "" + (${guessContentType.toString()})(pathname) });
                return new Response(body, { status: 200, headers });
              }
              return new Response("Not found in VFS: " + pathname, { status: 404 });
            }
          } catch (e) {
            // Ignore and fall back.
          }
          return realFetch(input, init);
        };
      })();
    </script>
    <script src="./bundless.sucrase.min.js" type="module"></script>
    <script src="${VFS_ORIGIN}${entryPath}" type="text/babel"></script>
  </body>
</html>`;
}

function defaultProject() {
  return {
    entry: "/app.jsx",
    files: {
      "/app.jsx": `import React from "react";\nimport ReactDOM from "react-dom";\n\nfunction App(){\n  return (\n    <div style={{fontFamily: 'sans-serif', padding: 12}}>\n      <h2>Preview Ready</h2>\n      <p>Ask the chatbot to generate a project.</p>\n    </div>\n  );\n}\n\nReactDOM.render(<App />, document.getElementById('react-root'));\n`,
    },
  };
}

function App() {
  const [apiKey, setApiKey] = useState(
    () => localStorage.getItem("apiKey") || ""
  );
  const [isProjectPopoverOpen, setIsProjectPopoverOpen] = useState(false);
  const [copyButtonText, setCopyButtonText] = useState("Copy JSON");

  const [project, setProject] = useState(() => {
    try {
      const raw = localStorage.getItem("generatedProject");
      if (raw) return JSON.parse(raw);
    } catch {
      // ignore
    }
    return defaultProject();
  });

  const [iframeSrcDoc, setIframeSrcDoc] = useState(() => buildIframeSrcDoc(project));

  const handleApiKeyChange = (e) => {
    const newApiKey = e.target.value;
    setApiKey(newApiKey);
    localStorage.setItem("apiKey", newApiKey);
  };

  useEffect(() => {
    try {
      localStorage.setItem("generatedProject", JSON.stringify(project));
    } catch {
      // ignore
    }
    setIframeSrcDoc(buildIframeSrcDoc(project));
  }, [project]);

  useEffect(() => {
    if (copyButtonText === "Copy JSON") return undefined;
    const timer = window.setTimeout(() => {
      setCopyButtonText("Copy JSON");
    }, 1500);
    return () => window.clearTimeout(timer);
  }, [copyButtonText]);

  useEffect(() => {
    if (!isProjectPopoverOpen) return undefined;
    const onKeyDown = (event) => {
      if (event.key === "Escape") {
        setIsProjectPopoverOpen(false);
      }
    };
    window.addEventListener("keydown", onKeyDown);
    return () => {
      window.removeEventListener("keydown", onKeyDown);
    };
  }, [isProjectPopoverOpen]);

  const exportProjectText = (() => {
    try {
      return JSON.stringify(project, null, 2);
    } catch {
      return String(project);
    }
  })();
  const entryPath = normalizeFilePath(project?.entry || "/app.jsx");

  const handleCopyProject = async () => {
    try {
      await navigator.clipboard.writeText(exportProjectText);
      setCopyButtonText("Copied");
    } catch (e) {
      console.error("Copy failed", e);
      setCopyButtonText("Copy failed");
    }
  };

  return (
    <div className="aide-shell">
      <div className="aide-orb aide-orb-left" />
      <div className="aide-orb aide-orb-right" />

      <button
        type="button"
        className={`project-popover-toggle ${isProjectPopoverOpen ? "open" : ""}`}
        onClick={() => setIsProjectPopoverOpen((v) => !v)}
        aria-controls="generated-project-popover"
        aria-expanded={isProjectPopoverOpen}
      >
        <span>Generated Project</span>
        <span className="project-popover-toggle-state">{isProjectPopoverOpen ? "Hide" : "Show"}</span>
      </button>

      {isProjectPopoverOpen && (
        <>
          <div
            className="project-popover-backdrop"
            onClick={() => setIsProjectPopoverOpen(false)}
          />

          <aside
            id="generated-project-popover"
            role="dialog"
            aria-modal="true"
            aria-label="Generated Project JSON"
            className="project-popover open"
          >
            <div className="project-popover-header">
              <h2>Generated Project (copy/paste)</h2>
              <button
                type="button"
                className="project-popover-close"
                onClick={() => setIsProjectPopoverOpen(false)}
                aria-label="Close generated project popover"
              >
                ×
              </button>
            </div>
            <p className="project-popover-subtitle">
              Full JSON state for the iframe runtime.
            </p>
            <div className="project-popover-actions">
              <button
                type="button"
                className="btn-primary"
                onClick={handleCopyProject}
              >
                {copyButtonText}
              </button>
              <button
                type="button"
                className="btn-ghost"
                onClick={() => {
                  setProject(defaultProject());
                }}
              >
                Reset Project
              </button>
            </div>
            <textarea
              value={exportProjectText}
              readOnly
              rows={16}
              className="project-popover-textarea"
            />
          </aside>
        </>
      )}

      <header className="aide-header">
        <div className="aide-header-copy">
          <p className="aide-eyebrow">AideApps Studio</p>
          <h1>Buildless React Playground</h1>
          <p>
            Prompt the assistant and watch changes render directly in the live iframe.
          </p>
        </div>
        <div className="aide-controls">
          <label className="api-key-card" htmlFor="api-key">
            <span>OpenAI API Key</span>
            <input
              type="password"
              id="api-key"
              value={apiKey}
              onChange={handleApiKeyChange}
              placeholder="Paste key for direct browser requests"
            />
          </label>
        </div>
      </header>

      <main className="aide-main">
        <section className="preview-panel">
          <div className="preview-panel-header">
            <h2>Live Preview</h2>
            <p className="entry-pill">Entry: {entryPath}</p>
          </div>
          <iframe
            id="output-frame"
            title="preview"
            className="preview-frame"
            srcDoc={iframeSrcDoc}
          />
        </section>
      </main>

      <div className="screen-reader-only" aria-live="polite">
        {copyButtonText}
      </div>
      <Chatbot
        apiKey={apiKey}
        project={project}
        onProjectUpdate={setProject}
        groupId={1}
        userId={1}
        viewId={"default-view"}
      />
    </div>
  );
}

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById("root")
);
