/**
 * Technique page detail view with version switching.
 *
 * Layout: sticky title bar at top of article, 2-column grid below.
 * Left column: prose, key moments (bibliography), signal chains, related techniques.
 * Right column: ToC (sticky, scrolls with viewer).
 */

import { useEffect, useMemo, useRef, useState } from "react";
import { Link, useParams } from "react-router-dom";
import {
  fetchTechnique,
  fetchTechniqueVersions,
  fetchTechniqueVersion,
  type TechniquePageDetail as TechniqueDetail,
  type TechniquePageVersionSummary,
  type TechniquePageVersionDetail,
  type BodySectionV2,
} from "../api";
import ReportIssueModal from "../components/ReportIssueModal";
import CopyLinkButton from "../components/CopyLinkButton";
import CreatorAvatar from "../components/CreatorAvatar";
import TableOfContents, { slugify } from "../components/TableOfContents";
import { parseCitations } from "../utils/citations";
import { useDocumentTitle } from "../hooks/useDocumentTitle";

function formatTime(seconds: number): string {
  const m = Math.floor(seconds / 60);
  const s = Math.floor(seconds % 60);
  return `${m}:${s.toString().padStart(2, "0")}`;
}

function formatDate(iso: string): string {
  return new Date(iso).toLocaleDateString("en-US", {
    year: "numeric",
    month: "short",
    day: "numeric",
    hour: "2-digit",
    minute: "2-digit",
  });
}

/** Extract the displayable fields from a version snapshot, matching TechniqueDetail shape. */
function snapshotToOverlay(snapshot: Record<string, unknown>) {
  let bodySections: BodySectionV2[] | Record<string, unknown> | undefined;
  if (Array.isArray(snapshot.body_sections)) {
    bodySections = snapshot.body_sections as BodySectionV2[];
  } else if (typeof snapshot.body_sections === "object" && snapshot.body_sections !== null) {
    bodySections = snapshot.body_sections as Record<string, unknown>;
  }

  return {
    title: typeof snapshot.title === "string" ? snapshot.title : undefined,
    summary: typeof snapshot.summary === "string" ? snapshot.summary : undefined,
    topic_category:
      typeof snapshot.topic_category === "string"
        ? snapshot.topic_category
        : undefined,
    topic_tags: Array.isArray(snapshot.topic_tags)
      ? (snapshot.topic_tags as string[])
      : undefined,
    body_sections: bodySections,
    body_sections_format:
      typeof snapshot.body_sections_format === "string"
        ? snapshot.body_sections_format
        : undefined,
    signal_chains: Array.isArray(snapshot.signal_chains)
      ? (snapshot.signal_chains as unknown[])
      : undefined,
    plugins: Array.isArray(snapshot.plugins)
      ? (snapshot.plugins as string[])
      : undefined,
    source_quality:
      typeof snapshot.source_quality === "string"
        ? snapshot.source_quality
        : undefined,
  };
}

export default function TechniquePage() {
  const { slug } = useParams<{ slug: string }>();
  const [technique, setTechnique] = useState<TechniqueDetail | null>(null);
  const [loading, setLoading] = useState(true);
  const [notFound, setNotFound] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [showReport, setShowReport] = useState(false);

  useDocumentTitle(technique ? `${technique.title} — Chrysopedia` : "Chrysopedia");

  // Version switching
  const [versions, setVersions] = useState<TechniquePageVersionSummary[]>([]);
  const [selectedVersion, setSelectedVersion] = useState<string>("current");
  const [versionDetail, setVersionDetail] =
    useState<TechniquePageVersionDetail | null>(null);
  const [versionLoading, setVersionLoading] = useState(false);

  // Load technique + version list
  useEffect(() => {
    if (!slug) return;

    let cancelled = false;
    setLoading(true);
    setNotFound(false);
    setError(null);
    setSelectedVersion("current");
    setVersionDetail(null);
    setVersions([]);

    void (async () => {
      try {
        const data = await fetchTechnique(slug);
        if (!cancelled) {
          setTechnique(data);
          if (data.version_count > 0) {
            try {
              const vRes = await fetchTechniqueVersions(slug);
              if (!cancelled) setVersions(vRes.items);
            } catch {
              // Non-critical
            }
          }
        }
      } catch (err) {
        if (!cancelled) {
          if (err instanceof Error && err.message.includes("404")) {
            setNotFound(true);
          } else {
            setError(
              err instanceof Error ? err.message : "Failed to load technique",
            );
          }
        }
      } finally {
        if (!cancelled) setLoading(false);
      }
    })();

    return () => {
      cancelled = true;
    };
  }, [slug]);

  // Load version detail when selection changes
  useEffect(() => {
    if (!slug || selectedVersion === "current") {
      setVersionDetail(null);
      return;
    }

    let cancelled = false;
    setVersionLoading(true);

    void (async () => {
      try {
        const detail = await fetchTechniqueVersion(
          slug,
          Number(selectedVersion),
        );
        if (!cancelled) setVersionDetail(detail);
      } catch {
        if (!cancelled) setVersionDetail(null);
      } finally {
        if (!cancelled) setVersionLoading(false);
      }
    })();

    return () => {
      cancelled = true;
    };
  }, [slug, selectedVersion]);

  // --- Scroll-spy: activeId for ToC ---
  const [activeId, setActiveId] = useState<string>("");
  const titleBarRef = useRef<HTMLDivElement>(null);

  // Overlay snapshot fields when viewing a historical version
  const isHistorical = selectedVersion !== "current" && versionDetail != null;
  const overlay = (isHistorical && technique)
    ? snapshotToOverlay(versionDetail.content_snapshot)
    : null;

  const displaySections = technique ? (overlay?.body_sections ?? technique.body_sections) : null;
  const displayFormat = technique ? (overlay?.body_sections_format ?? technique.body_sections_format ?? "v1") : "v1";

  // Build flat list of all section/subsection IDs for observation
  const allSectionIds = useMemo(() => {
    if (displayFormat !== "v2" || !Array.isArray(displaySections)) return [];
    const ids: string[] = [];
    for (const section of displaySections as BodySectionV2[]) {
      const sectionSlug = slugify(section.heading);
      ids.push(sectionSlug);
      for (const sub of section.subsections) {
        ids.push(`${sectionSlug}--${slugify(sub.heading)}`);
      }
    }
    return ids;
  }, [displayFormat, displaySections]);

  // Observe section headings — drives activeId for ToC
  useEffect(() => {
    if (allSectionIds.length === 0) return;
    const observer = new IntersectionObserver(
      (entries) => {
        const intersecting = entries
          .filter((e) => e.isIntersecting)
          .sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top);
        if (intersecting.length > 0) {
          setActiveId(intersecting[0]!.target.id);
        }
      },
      { rootMargin: "0px 0px -70% 0px" }
    );
    for (const id of allSectionIds) {
      const el = document.getElementById(id);
      if (el) observer.observe(el);
    }
    return () => observer.disconnect();
  }, [allSectionIds]);

  // Scroll to hash fragment after technique loads
  useEffect(() => {
    if (!technique) return;
    const hash = window.location.hash.slice(1);
    if (hash) {
      const el = document.getElementById(hash);
      if (el) {
        el.scrollIntoView({ behavior: "smooth", block: "start" });
      }
    }
  }, [technique]);

  if (loading) {
    return <div className="loading">Loading technique…</div>;
  }

  if (notFound) {
    return (
      <div className="technique-404">
        <h2>Technique Not Found</h2>
        <p>The technique &ldquo;{slug}&rdquo; doesn&rsquo;t exist.</p>
        <Link to="/" className="btn">
          Back to Home
        </Link>
      </div>
    );
  }

  if (error || !technique) {
    return (
      <div className="loading error-text">
        Error: {error ?? "Unknown error"}
      </div>
    );
  }

  // Re-derive display fields now that we know technique is non-null
  const displayTitle = overlay?.title ?? technique.title;
  const displaySummary = overlay?.summary ?? technique.summary;
  const displayCategory = overlay?.topic_category ?? technique.topic_category;
  const displayTags = overlay?.topic_tags ?? technique.topic_tags;
  const displayChains = overlay?.signal_chains ?? technique.signal_chains;
  const displayPlugins = overlay?.plugins ?? technique.plugins;
  const displayQuality = overlay?.source_quality ?? technique.source_quality;

  const isV2 = displayFormat === "v2" && Array.isArray(displaySections) && (displaySections as BodySectionV2[]).length > 0;

  return (
    <article className="technique-page">
      {/* Historical version banner */}
      {isHistorical && (
        <div className="technique-banner technique-banner--version">
          📋 Viewing version {versionDetail.version_number} from{" "}
          {formatDate(versionDetail.created_at)}
          <button
            className="btn btn--small btn--primary"
            style={{ marginLeft: "1rem" }}
            onClick={() => setSelectedVersion("current")}
          >
            Back to current
          </button>
        </div>
      )}

      {/* Unstructured content warning */}
      {displayQuality === "unstructured" && (
        <div className="technique-banner technique-banner--amber">
          ⚠ This technique was sourced from a livestream and may have less
          structured content.
        </div>
      )}

      {/* Sticky title bar — sits at top of article, becomes sticky on scroll */}
      <div className="technique-title-bar" ref={titleBarRef}>
        <div className="technique-title-bar__inner">
          <h1 className="technique-title-bar__title">
            <Link to="/" className="technique-title-bar__back" aria-label="Back to home">←</Link>
            {displayTitle} <CopyLinkButton />
          </h1>
          <div className="technique-title-bar__meta">
            {displayCategory && (
              <span className={"badge badge--category badge--cat-" + (displayCategory?.toLowerCase().replace(/\s+/g, "-") ?? "")}>
                {displayCategory}
              </span>
            )}
            {technique.creator_info && (
              <Link to={`/creators/${technique.creator_info.slug}`} className="technique-title-bar__creator">
                <CreatorAvatar creatorId={String(technique.creator_info.slug)} name={technique.creator_info.name} size={20} />
                {technique.creator_info.name}
              </Link>
            )}
          </div>
        </div>
      </div>

      {/* Report modal */}
      {showReport && (
        <ReportIssueModal
          contentType="technique_page"
          contentId={technique.id}
          contentTitle={technique.title}
          onClose={() => setShowReport(false)}
        />
      )}

      {/* Two-column layout: main content + ToC sidebar */}
      <div className="technique-columns">
        <div className="technique-columns__main">
          {/* Stats + version switcher */}
          <div className="technique-header__stats">
            {(() => {
              const sourceCount = new Set(
                technique.key_moments
                  .map((km) => km.video_filename)
                  .filter(Boolean),
              ).size;
              const momentCount = technique.key_moments.length;
              const updated = new Date(technique.updated_at).toLocaleDateString(
                "en-US",
                { year: "numeric", month: "short", day: "numeric" },
              );
              const parts = [
                `Compiled from ${sourceCount} source${sourceCount !== 1 ? "s" : ""}`,
                `${momentCount} key moment${momentCount !== 1 ? "s" : ""}`,
              ];
              if (technique.version_count > 0) {
                parts.push(
                  `${technique.version_count} version${technique.version_count !== 1 ? "s" : ""}`,
                );
              }
              parts.push(`Last updated ${updated}`);
              return parts.join(" · ");
            })()}
          </div>

          <div className="technique-header__actions">
            {versions.length > 0 && (
              <div className="version-switcher">
                <label className="version-switcher__label">Version:</label>
                <select
                  className="version-switcher__select"
                  value={selectedVersion}
                  onChange={(e) => setSelectedVersion(e.target.value)}
                  disabled={versionLoading}
                >
                  <option value="current">Current (live)</option>
                  {versions.map((v) => (
                    <option key={v.version_number} value={String(v.version_number)}>
                      v{v.version_number} — {formatDate(v.created_at)}
                    </option>
                  ))}
                </select>
                {versionLoading && (
                  <span className="version-switcher__loading">Loading…</span>
                )}
              </div>
            )}
          </div>

          {/* Pipeline metadata for historical versions */}
          {isHistorical && versionDetail.pipeline_metadata && (
            <div className="version-metadata">
              <h4 className="version-metadata__title">Pipeline metadata (v{versionDetail.version_number})</h4>
              <div className="version-metadata__grid">
                {"model" in versionDetail.pipeline_metadata && (
                  <div className="version-metadata__item">
                    <span className="version-metadata__key">Model</span>
                    <span className="version-metadata__value">
                      {String(versionDetail.pipeline_metadata.model)}
                    </span>
                  </div>
                )}
                {"captured_at" in versionDetail.pipeline_metadata && (
                  <div className="version-metadata__item">
                    <span className="version-metadata__key">Captured</span>
                    <span className="version-metadata__value">
                      {formatDate(String(versionDetail.pipeline_metadata.captured_at))}
                    </span>
                  </div>
                )}
                {typeof versionDetail.pipeline_metadata.prompt_hashes === "object" &&
                  versionDetail.pipeline_metadata.prompt_hashes !== null && (
                    <div className="version-metadata__item version-metadata__item--wide">
                      <span className="version-metadata__key">Prompt hashes</span>
                      <div className="version-metadata__hashes">
                        {Object.entries(
                          versionDetail.pipeline_metadata.prompt_hashes as Record<
                            string,
                            string
                          >,
                        ).map(([file, hash]) => (
                          <div key={file} className="version-metadata__hash">
                            <span className="version-metadata__hash-file">
                              {file.replace(/^.*\//, "")}
                            </span>
                            <code className="version-metadata__hash-value">
                              {hash.slice(0, 12)}…
                            </code>
                          </div>
                        ))}
                      </div>
                    </div>
                  )}
              </div>
            </div>
          )}

          {/* Tags + plugin pills */}
          {((displayTags && displayTags.length > 0) || (displayPlugins && displayPlugins.length > 0)) && (
            <div className="technique-main__tags">
              {displayTags && displayTags.map((tag) => (
                <span key={tag} className="pill">
                  {tag}
                </span>
              ))}
              {displayPlugins && displayPlugins.length > 0 && displayPlugins.map((plugin) => (
                <span key={`plugin-${plugin}`} className="pill pill--plugin">
                  {plugin}
                </span>
              ))}
            </div>
          )}

          {/* Summary */}
          {displaySummary && (
            <section className="technique-summary">
              <p>{displaySummary}</p>
            </section>
          )}

          {/* Study guide prose — body_sections */}
          {displaySections &&
            (Array.isArray(displaySections) ? displaySections.length > 0 : Object.keys(displaySections).length > 0) && (
              <section className="technique-prose">
                {displayFormat === "v2" && Array.isArray(displaySections) ? (
                  <>
                    {(displaySections as BodySectionV2[]).map((section) => {
                      const sectionSlug = slugify(section.heading);
                      return (
                        <div key={sectionSlug} className="technique-prose__section" id={sectionSlug}>
                          <h2>{section.heading}</h2>
                          {section.content && (
                            <p>{parseCitations(section.content, technique.key_moments)}</p>
                          )}
                          {section.subsections.map((sub) => {
                            const subSlug = `${sectionSlug}--${slugify(sub.heading)}`;
                            return (
                              <div key={subSlug} className="technique-prose__subsection" id={subSlug}>
                                <h3>{sub.heading}</h3>
                                {sub.content && (
                                  <p>{parseCitations(sub.content, technique.key_moments)}</p>
                                )}
                              </div>
                            );
                          })}
                        </div>
                      );
                    })}
                  </>
                ) : (
                  /* V1 dict format */
                  Object.entries(displaySections as Record<string, unknown>).map(
                    ([sectionTitle, content]: [string, unknown]) => (
                      <div key={sectionTitle} className="technique-prose__section">
                        <h2>{sectionTitle}</h2>
                        {typeof content === "string" ? (
                          <p>{content as string}</p>
                        ) : typeof content === "object" && content !== null ? (
                          <pre className="technique-prose__json">
                            {JSON.stringify(content, null, 2)}
                          </pre>
                        ) : (
                          <p>{String(content as string)}</p>
                        )}
                      </div>
                    ),
                  )
                )}
              </section>
            )}

          {/* Key Moments — bibliography style */}
          {technique.key_moments.length > 0 && (
            <section className="technique-sources">
              <h2>Key Moments</h2>
              <ol className="technique-sources__list">
                {technique.key_moments.map((km, idx) => (
                  <li key={km.id} id={`km-${km.id}`} className="technique-source">
                    <span className="technique-source__index">[{idx}]</span>
                    <div className="technique-source__body">
                      <span className="technique-source__title">{km.title}</span>
                      <span className="technique-source__detail">
                        {km.video_filename && (
                          <span className="technique-source__file">{km.video_filename}</span>
                        )}
                        {km.source_video_id ? (
                          <Link
                            to={`/watch/${km.source_video_id}?t=${km.start_time}`}
                            className="technique-source__time technique-source__time--link"
                          >
                            {formatTime(km.start_time)}–{formatTime(km.end_time)}
                          </Link>
                        ) : (
                          <span className="technique-source__time">
                            {formatTime(km.start_time)}–{formatTime(km.end_time)}
                          </span>
                        )}
                        <span className="technique-source__type">{km.content_type}</span>
                      </span>
                      <span className="technique-source__summary">{km.summary}</span>
                    </div>
                  </li>
                ))}
              </ol>
            </section>
          )}

          {/* Signal chains */}
          {displayChains &&
            displayChains.length > 0 && (
              <section className="technique-chains">
                <h2>Signal Chains</h2>
                {displayChains.map((chain, i) => {
                  const chainObj = chain as Record<string, unknown>;
                  const chainName =
                    typeof chainObj["name"] === "string"
                      ? chainObj["name"]
                      : `Chain ${i + 1}`;
                  const steps = Array.isArray(chainObj["steps"])
                    ? (chainObj["steps"] as string[])
                    : [];
                  return (
                    <div key={i} className="technique-chain">
                      <h3>{chainName}</h3>
                      {steps.length > 0 && (
                        <div className="technique-chain__flow">
                          {steps.map((step, j) => (
                            <span key={j}>
                              {j > 0 && (
                                <span className="technique-chain__arrow">
                                  {" → "}
                                </span>
                              )}
                              <span className="technique-chain__step">
                                {String(step)}
                              </span>
                            </span>
                          ))}
                        </div>
                      )}
                    </div>
                  );
                })}
              </section>
            )}

          {/* Related techniques — styled as cards matching homepage Recently Added */}
          {technique.related_links.length > 0 && (
            <section className="technique-related">
              <h2>Related Techniques</h2>
              <div className="technique-related__grid">
                {technique.related_links.map((link) => (
                  <Link key={link.target_slug} to={`/techniques/${link.target_slug}`} className="recent-card">
                    <span className="recent-card__title">{link.target_title}</span>
                    <span className="recent-card__meta">
                      {link.topic_category && (
                        <span className="badge badge--category">
                          {link.topic_category}
                        </span>
                      )}
                      {link.reason && (
                        <span className="recent-card__summary">{link.reason}</span>
                      )}
                    </span>
                    <span className="recent-card__footer">
                      <span className="recent-card__creator">
                        {link.creator_name || ''}
                      </span>
                    </span>
                  </Link>
                ))}
              </div>
            </section>
          )}
        </div>

        {/* Sidebar: ToC only */}
        {isV2 && (
          <aside className="technique-columns__sidebar">
            <TableOfContents sections={displaySections as BodySectionV2[]} activeId={activeId} />
          </aside>
        )}
      </div>

      {/* Footer actions */}
      <div className="technique-footer">
        <button
          className="btn btn--ghost btn--small"
          onClick={() => setShowReport(true)}
        >
          ⚑ Report issue with this page
        </button>
        {technique.key_moments.length > 0 && technique.key_moments[0]?.source_video_id && (
          <Link
            to={`/admin/pipeline?video=${technique.key_moments[0].source_video_id}`}
            className="btn btn--ghost btn--small technique-footer__inspect"
            title="View pipeline job for this article"
          >
            <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
              <circle cx="11" cy="11" r="7" />
              <line x1="16.5" y1="16.5" x2="21" y2="21" />
              <line x1="11" y1="8" x2="11" y2="14" />
              <line x1="8" y1="11" x2="14" y2="11" />
            </svg>
            Inspect pipeline
          </Link>
        )}
      </div>
    </article>
  );
}
