import { useEffect, useMemo, useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import { api } from "../lib/api";
import type { SubmitLandmarksRequest } from "../lib/api";
import { LandmarkCanvas } from "../components/LandmarkCanvas";
import type { Point } from "../components/LandmarkCanvas";

const API_BASE = "https://cfx9z50wj2.execute-api.ca-central-1.amazonaws.com/prod";

type AnyObj = Record<string, any>;

async function httpJson<T>(path: string, init?: RequestInit): Promise<T> {
  const base = API_BASE.replace(/\/+$/, "");
  const normalizedPath = path.startsWith("/") ? path : `/${path}`;
  const url = `${base}${normalizedPath}`;

  const res = await fetch(url, {
    ...init,
    headers: {
      "Content-Type": "application/json",
      ...(init?.headers || {}),
    },
  });

  if (!res.ok) {
    const text = await res.text().catch(() => "");
    throw new Error(`HTTP ${res.status} ${res.statusText}: ${text}`);
  }

  return (await res.json()) as T;
}

function buildPublicS3Url(bucket: string, key: string) {
  return `https://${bucket}.s3.amazonaws.com/${key}`;
}

async function tryResolveApUrlFromApi(caseId: string): Promise<string | null> {
  const candidates: Array<{
    method: "GET" | "POST";
    path: string;
    body?: any;
    pickUrl: (json: AnyObj) => string | null;
  }> = [
    {
      method: "GET",
      path: `/cases/${encodeURIComponent(caseId)}/xray-url?view=ap`,
      pickUrl: (j) => j?.url || j?.downloadUrl || j?.imageUrl || null,
    },
    {
      method: "GET",
      path: `/cases/${encodeURIComponent(caseId)}/xray-preview?view=ap`,
      pickUrl: (j) => j?.url || j?.downloadUrl || j?.imageUrl || null,
    },
    {
      method: "GET",
      path: `/cases/${encodeURIComponent(caseId)}/download-url?type=xray&view=ap`,
      pickUrl: (j) => j?.url || j?.downloadUrl || j?.imageUrl || null,
    },
    {
      method: "POST",
      path: `/cases/${encodeURIComponent(caseId)}/download-url`,
      body: { type: "xray", view: "ap" },
      pickUrl: (j) => j?.url || j?.downloadUrl || j?.imageUrl || null,
    },
    {
      method: "POST",
      path: `/cases/${encodeURIComponent(caseId)}/file-url`,
      body: { kind: "xray", view: "ap" },
      pickUrl: (j) => j?.url || j?.downloadUrl || j?.imageUrl || null,
    },
  ];

  for (const c of candidates) {
    try {
      const json =
        c.method === "GET"
          ? await httpJson<AnyObj>(c.path)
          : await httpJson<AnyObj>(c.path, {
              method: "POST",
              body: JSON.stringify(c.body ?? {}),
            });

      const url = c.pickUrl(json);
      if (url && typeof url === "string") return url;
    } catch {
      // ignore and continue
    }
  }

  return null;
}

function assetHasAp(assets: AnyObj | null): boolean {
  if (!assets) return false;
  const xr = assets.xrays ?? assets.assets?.xrays;

  if (Array.isArray(xr)) return xr.includes("ap");
  if (xr && typeof xr === "object") return !!xr.ap;
  if (typeof assets.apImageUrl === "string" && assets.apImageUrl) return true;

  return false;
}

function pickApUrlFromAssets(assets: AnyObj | null): string | null {
  if (!assets) return null;
  const a = assets.assets ?? assets;

  if (typeof a.apImageUrl === "string" && a.apImageUrl) return a.apImageUrl;
  if (typeof a.xrays?.ap === "string" && a.xrays.ap) return a.xrays.ap;

  const apObj = a?.ap || a?.xrays?.ap || a?.assets?.xrays?.ap;
  if (apObj && apObj.bucket && apObj.key) return buildPublicS3Url(apObj.bucket, apObj.key);

  const apUrl = a?.xrays?.ap?.url || a?.xrays?.ap?.downloadUrl || a?.xrays?.ap?.imageUrl;
  if (typeof apUrl === "string" && apUrl) return apUrl;

  return null;
}

function jsonPretty(v: any) {
  try {
    return JSON.stringify(v, null, 2);
  } catch {
    return String(v);
  }
}

type ArtifactTab = { n: number; label: string; path: string };
type ArtifactState = { loading: boolean; error: string | null; json: any | null; lastLoadedAt?: number };

function buildArtifactUrl(caseId: string, path: string) {
  return `https://braceflow-uploads-20260125.s3.ca-central-1.amazonaws.com/cases/${encodeURIComponent(caseId)}/${path}`;
}

export function LandmarkCapturePage() {
  const { caseId } = useParams();
  const nav = useNavigate();
  const id = (caseId || "").trim();

  const [assets, setAssets] = useState<AnyObj | null>(null);
  const [assetsLoaded, setAssetsLoaded] = useState(false);

  const [imageUrl, setImageUrl] = useState<string>("");
  const [imageLoading, setImageLoading] = useState(false);
  const [imageError, setImageError] = useState<string | null>(null);

  const [manualUrl, setManualUrl] = useState<string>("");

  // ✅ FIX: was Point[]; must be Record<string, Point> to match LandmarkCanvas + SubmitLandmarksRequest
  const [landmarks, setLandmarks] = useState<Record<string, Point>>({});
  const [completed, setCompleted] = useState(false);

  const [submitting, setSubmitting] = useState(false);
  const [msg, setMsg] = useState<string | null>(null);

  // --- Artifacts slide panel ---
  const [artifactsOpen, setArtifactsOpen] = useState(false);
  const [activeArtifactIdx, setActiveArtifactIdx] = useState(0);
  const [artifactStateByIdx, setArtifactStateByIdx] = useState<Record<number, ArtifactState>>({});

  const artifactTabs: ArtifactTab[] = useMemo(
    () => [
      { n: 1, label: "1", path: "step1_normalized/meta.json" },
      { n: 2, label: "2", path: "step2_measurements/landmarks.json" },
      { n: 3, label: "3", path: "step2_measurements/measurements.json" },
      { n: 4, label: "4", path: "step3_rigo/classification.json" },
      { n: 5, label: "5", path: "step4_template/template.json" },
      { n: 6, label: "6", path: "step5_deformation/brace_spec.json" },
      { n: 7, label: "7", path: "step6_export/print_manifest.json" },
    ],
    []
  );

  const apExists = useMemo(() => assetHasAp(assets), [assets]);

  const codeBoxStyle: React.CSSProperties = {
    border: "1px solid rgba(255,255,255,0.08)",
    borderRadius: 10,
    padding: 12,
    background: "rgba(0,0,0,0.20)",
    overflow: "auto",
    whiteSpace: "pre-wrap",
    wordBreak: "break-word",
  };

  const linkStyle: React.CSSProperties = {
    textDecoration: "underline",
    fontWeight: 700,
    opacity: 0.95,
  };

  async function loadAssetsAndResolveImage() {
    if (!id) {
      setMsg("No case id in route.");
      return;
    }

    setAssetsLoaded(false);
    setMsg(null);
    setImageError(null);

    try {
      const a = await httpJson<AnyObj>(`/cases/${encodeURIComponent(id)}/assets`);
      setAssets(a);

      const direct = pickApUrlFromAssets(a);
      if (direct) {
        setImageLoading(true);
        setImageUrl(direct);
        return;
      }

      if (assetHasAp(a)) {
        const resolved = await tryResolveApUrlFromApi(id);
        if (resolved) {
          setImageLoading(true);
          setImageUrl(resolved);
          return;
        }

        setImageUrl("");
        setImageError(
          "AP x-ray exists (assets.xrays includes 'ap') but no viewable image URL was returned. " +
            "Backend likely needs a presigned GET/preview endpoint (e.g., /cases/{caseId}/xray-url?view=ap). " +
            "Use the manual URL field below as a temporary workaround."
        );
        return;
      }

      setImageUrl("");
      setImageError(null);
    } catch (e: any) {
      setMsg(e?.message || "Failed to load assets");
    } finally {
      setAssetsLoaded(true);
    }
  }

  async function loadArtifactAt(idx: number) {
    if (!id) {
      setArtifactStateByIdx((p) => ({
        ...p,
        [idx]: { loading: false, error: "Missing caseId in route.", json: null },
      }));
      return;
    }

    const tab = artifactTabs[idx];
    if (!tab) return;

    setArtifactStateByIdx((p) => ({
      ...p,
      [idx]: { ...(p[idx] ?? { json: null, error: null }), loading: true, error: null },
    }));

    const url = buildArtifactUrl(id, tab.path);

    try {
      const res = await fetch(url);
      if (!res.ok) {
        const text = await res.text().catch(() => "");
        throw new Error(`HTTP ${res.status} ${res.statusText}${text ? `: ${text}` : ""}`);
      }
      const json = await res.json();
      setArtifactStateByIdx((p) => ({
        ...p,
        [idx]: { loading: false, error: null, json, lastLoadedAt: Date.now() },
      }));
    } catch (e: any) {
      setArtifactStateByIdx((p) => ({
        ...p,
        [idx]: { loading: false, error: e?.message || "Failed to load JSON", json: null },
      }));
    }
  }

  useEffect(() => {
    loadAssetsAndResolveImage();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [id]);

  useEffect(() => {
    if (!artifactsOpen) return;
    const st = artifactStateByIdx[activeArtifactIdx];
    if (!st || (!st.loading && st.json == null && st.error == null)) {
      loadArtifactAt(activeArtifactIdx);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [artifactsOpen, activeArtifactIdx]);

  useEffect(() => {
    if (!artifactsOpen) return;
    const onKeyDown = (e: KeyboardEvent) => {
      if (e.key === "Escape") setArtifactsOpen(false);
    };
    window.addEventListener("keydown", onKeyDown);
    return () => window.removeEventListener("keydown", onKeyDown);
  }, [artifactsOpen]);

  async function onSubmit() {
    if (!id) {
      setMsg("No case id");
      return;
    }

    setSubmitting(true);
    setMsg(null);
    try {
      const body: SubmitLandmarksRequest = { caseId: id, view: "ap", landmarks };
      const res = await api.submitLandmarks(id, body);

      if (res?.ok) {
        setMsg("Landmarks submitted. Pipeline should resume from Step2.");
        nav(`/cases/${encodeURIComponent(id)}/status`);
      } else {
        setMsg("Submission completed but response did not include ok=true.");
      }
    } catch (e: any) {
      setMsg(e?.message || "Failed to submit landmarks");
    } finally {
      setSubmitting(false);
    }
  }

  const activeTab = artifactTabs[activeArtifactIdx];
  const activeUrl = activeTab && id ? buildArtifactUrl(id, activeTab.path) : "";
  const activeState = artifactStateByIdx[activeArtifactIdx] ?? { loading: false, error: null, json: null };
  const canSubmit = completed && !submitting && !!imageUrl;

  return (
    <div className="bf-page bf-page--wide">
      <div className="bf-page-header">
        <div>
          <h1 className="bf-page-title">Landmark Capture</h1>
          <p className="bf-page-subtitle">
            Place landmarks on the AP X-ray, then submit to resume the pipeline.
          </p>
        </div>
        <div className="bf-spacer" />
        <div className="bf-toolbar">
          <button className="btn secondary" onClick={() => setArtifactsOpen(true)}>
            Artifacts
          </button>
          <button className="btn secondary" onClick={() => nav(`/cases/${encodeURIComponent(id)}/status`)}>
            View Status
          </button>
          <button className="btn secondary" onClick={() => loadAssetsAndResolveImage()}>
            Reload Assets
          </button>
          <button className="btn primary" disabled={!canSubmit} onClick={onSubmit}>
            {submitting ? "Submitting..." : "Submit Landmarks"}
          </button>
        </div>
      </div>

      <div className="card">
        <div className="muted muted--tight">
          Case: <strong>{id || "(missing)"}</strong>
        </div>

      {msg && <div className="notice">{msg}</div>}

      {!assetsLoaded ? (
        <div className="muted">Loading assets...</div>
      ) : (
        <>
          <div className="bf-row-gap-16">
            <div className="bf-flex-1">
              {imageUrl ? (
                <div>
                  <div className="bf-mb-8">
                    {imageLoading && <div className="muted">Loading image…</div>}
                    {imageError && <div className="error">{imageError}</div>}
                  </div>

                  {/* ============================
                      Thumbnail on top + Workspace below
                      ============================ */}
                  <div className="lc-stack">
                    {/* Thumbnail */}
                    <div className="lc-thumbRow">
                      <div className="lc-thumbCol">
                        <div className="lc-thumbBox">
                          <img
                            src={imageUrl}
                            alt="AP x-ray thumbnail"
                            onLoad={() => {
                              setImageLoading(false);
                              setImageError(null);
                            }}
                            onError={() => {
                              setImageLoading(false);
                              setImageError(
                                "Image failed to load. Most common causes: (1) URL is not public/presigned, (2) S3 CORS blocks browser, (3) URL points to a DICOM (not browser-renderable)."
                              );
                            }}
                          />
                        </div>

                        <div className="lc-thumbActions">
                          <button className="btn secondary" onClick={() => window.open(imageUrl, "_blank")}>
                            Open
                          </button>
                          <button
                            className="btn secondary"
                            onClick={() => {
                              setImageLoading(true);
                              setImageError(null);
                              setImageUrl(imageUrl);
                            }}
                          >
                            Reload
                          </button>
                        </div>

                        {imageLoading && <div className="muted">Loading image…</div>}
                      </div>
                    </div>

                    {/* Workspace */}
                    <div className="lc-workspace">
                      <div className="lc-workspace-title muted">Landmark capture</div>

                      {/* IMPORTANT: do NOT wrap LandmarkCanvas in a 250x250 box.
                          We will constrain ONLY the image holder via CSS. */}
                      <div className="lc-workspace-body">
                        <LandmarkCanvas
                          imageUrl={imageUrl}
                          initialLandmarks={landmarks}
                          onChange={(lm, done) => {
                            setLandmarks(lm);
                            setCompleted(done);
                          }}
                        />
                      </div>
                    </div>
                  </div>
                  {/* ============================ */}
                </div>
              ) : (
                <div className="bf-dashed-panel">
                  <div className="muted">
                    {apExists
                      ? "AP x-ray exists for this case, but no viewable URL is available yet."
                      : "AP image not available for this case."}
                  </div>

                  <div className="bf-mt-12">
                    <div className="muted bf-mb-6">
                      Temporary workaround: paste a viewable image URL (presigned GET to a JPG/PNG).
                    </div>
                    <div className="row gap">
                      <input
                        className="input"
                        placeholder="https://... (presigned GET to preview image)"
                        value={manualUrl}
                        onChange={(e) => setManualUrl(e.target.value)}
                      />
                      <button
                        className="btn"
                        onClick={() => {
                          if (!manualUrl.trim()) return;
                          setImageLoading(true);
                          setImageError(null);
                          setImageUrl(manualUrl.trim());
                        }}
                      >
                        Use URL
                      </button>
                    </div>
                  </div>

                  <div className="bf-mt-12">
                    <button className="btn" onClick={() => nav(`/cases/${encodeURIComponent(id)}/xray`)}>
                      Upload AP X-ray
                    </button>
                  </div>

                  {imageError && (
                    <div className="error bf-mt-12">
                      {imageError}
                    </div>
                  )}
                </div>
              )}
            </div>
          </div>

        </>
      )}
      </div>

      {/* ==========================
          Slide-in Artifacts Drawer
          ========================== */}
      <div
        className={`bf-drawer-backdrop ${artifactsOpen ? "is-open" : ""}`}
        onClick={() => setArtifactsOpen(false)}
        role="presentation"
      />

      <aside className={`bf-drawer ${artifactsOpen ? "is-open" : ""}`} aria-hidden={!artifactsOpen}>
        <div className="bf-drawer-header">
          <div className="bf-col-tight">
            <div className="bf-drawer-title">Artifacts</div>
            <div className="bf-drawer-subtitle">Case: {id || "(missing)"}</div>
          </div>
          <button className="btn secondary" onClick={() => setArtifactsOpen(false)}>
            Close
          </button>
        </div>

        <div className="bf-tabs">
          {artifactTabs.map((t, idx) => (
            <button
              key={t.n}
              className={`bf-tab ${idx === activeArtifactIdx ? "is-active" : ""}`}
              onClick={() => setActiveArtifactIdx(idx)}
              title={t.path}
            >
              {t.label}
            </button>
          ))}
        </div>

        <div className="bf-drawer-body">
          <div className="row space center">
            <div className="bf-col-tight">
              <div className="bf-strong">Artifact {activeTab?.label}</div>
              <div className="muted muted--small bf-ellipsis">
                {activeTab?.path}
              </div>
            </div>

            <div className="bf-row-end-wrap">
              <button className="btn secondary" onClick={() => window.open(activeUrl, "_blank")} disabled={!activeUrl}>
                Open JSON
              </button>
              <button
                className="btn secondary"
                onClick={() => loadArtifactAt(activeArtifactIdx)}
                disabled={!id || activeState.loading}
              >
                {activeState.loading ? "Loading…" : "Reload"}
              </button>
            </div>
          </div>

          {activeState.error && (
            <div className="error bf-mt-10">
              {activeState.error}
            </div>
          )}

          <div className="bf-mt-12">
            <pre style={codeBoxStyle}>
              {activeState.loading ? "Loading…" : activeState.json ? jsonPretty(activeState.json) : "(not available yet)"}
            </pre>
          </div>

          <div className="bf-mt-14">
            <div className="muted muted--small bf-mb-6">
              Assets (debug)
            </div>
            <pre style={codeBoxStyle}>{jsonPretty(assets ?? {})}</pre>
            <div className="bf-mt-10">
              <div className="muted">AP exists: {String(apExists)}</div>
              <div className="muted">Image URL resolved: {imageUrl ? "yes" : "no"}</div>
              {activeUrl && (
                <div className="muted">
                  URL:{" "}
                  <a style={linkStyle} href={activeUrl} target="_blank" rel="noreferrer">
                    {activeUrl}
                  </a>
                </div>
              )}
            </div>
          </div>
        </div>
      </aside>
    </div>
  );
}

