import { createElement, useEffect, useMemo, useState, type CSSProperties } from "react";
import {
  iconPacks,
  iconSemantics,
  type IconPack,
  type IconPosture,
  type IconSemantic,
} from "./iconPacks";
import "./iconExplorer.css";

type ExplorerView = "evaluate" | "catalog" | "compare";
type Appearance = "default" | "rounded" | "sharp";
type Density = "comfortable" | "compact";

type CatalogResponse = {
  total?: number;
  title?: string;
  categories?: Record<string, string[]>;
  uncategorized?: string[];
};

type CatalogRow = {
  name: string;
  category: string;
};

type CatalogState =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "error"; message: string }
  | { status: "loaded"; total: number; title: string; rows: CatalogRow[] };

const postureOptions: Array<{ value: "all" | IconPosture; label: string }> = [
  { value: "all", label: "All candidates" },
  { value: "shortlist", label: "Shortlist" },
  { value: "broad", label: "Broad coverage" },
  { value: "specialized", label: "Specialized" },
  { value: "brand", label: "Brand logos" },
];

function Icon({ name, size = 18, className }: { name: string; size?: number; className?: string }) {
  return createElement("iconify-icon", {
    icon: name,
    width: size,
    height: size,
    class: className,
    "aria-hidden": "true",
  });
}

function collectionToRows(collection: CatalogResponse) {
  const rows: CatalogRow[] = [];
  const seen = new Set<string>();

  Object.entries(collection.categories ?? {}).forEach(([category, names]) => {
    names.forEach((name) => {
      if (seen.has(name)) return;
      seen.add(name);
      rows.push({ name, category });
    });
  });

  (collection.uncategorized ?? []).forEach((name) => {
    if (seen.has(name)) return;
    seen.add(name);
    rows.push({ name, category: "Uncategorized" });
  });

  return rows;
}

export function IconExplorer() {
  const [activePackId, setActivePackId] = useState("lucide");
  const [activeVariantByPack, setActiveVariantByPack] = useState<Record<string, string>>({});
  const [view, setView] = useState<ExplorerView>("evaluate");
  const [packQuery, setPackQuery] = useState("");
  const [postureFilter, setPostureFilter] = useState<"all" | IconPosture>("all");
  const [iconSize, setIconSize] = useState(18);
  const [appearance, setAppearance] = useState<Appearance>("default");
  const [density, setDensity] = useState<Density>("comfortable");
  const [catalogs, setCatalogs] = useState<Record<string, CatalogState>>({});
  const [catalogQuery, setCatalogQuery] = useState("");
  const [catalogCategory, setCatalogCategory] = useState("all");
  const [renderLimit, setRenderLimit] = useState(180);

  useEffect(() => {
    if (document.querySelector('script[data-iconify-icon="true"]')) return;

    const script = document.createElement("script");
    script.src = "https://code.iconify.design/iconify-icon/3.0.0/iconify-icon.min.js";
    script.async = true;
    script.dataset.iconifyIcon = "true";
    document.head.appendChild(script);
  }, []);

  const activePack = useMemo(
    () => iconPacks.find((pack) => pack.id === activePackId) ?? iconPacks[0],
    [activePackId],
  );

  const activeVariant = useMemo(() => {
    const id = activeVariantByPack[activePack.id] ?? activePack.variants[0].id;
    return activePack.variants.find((variant) => variant.id === id) ?? activePack.variants[0];
  }, [activePack, activeVariantByPack]);

  function getIconName(pack: IconPack, semantic: IconSemantic) {
    const variantId = activeVariantByPack[pack.id] ?? pack.variants[0].id;
    const variant = pack.variants.find((item) => item.id === variantId) ?? pack.variants[0];
    const override = variant.overrides?.[semantic];
    let base = override ?? pack.icons[semantic] ?? pack.icons.home;

    if (!override && pack.variantMode === "prefix" && variant.prefix) {
      base = `${variant.prefix}${base}`;
    }

    if (!override && pack.variantMode === "suffix" && variant.suffix) {
      base = `${base}${variant.suffix}`;
    }

    return `${pack.prefix}:${base}`;
  }

  const filteredPacks = useMemo(() => {
    const query = packQuery.trim().toLowerCase();
    return iconPacks.filter((pack) => {
      const matchesQuery = `${pack.name} ${pack.license} ${pack.tags.join(" ")}`
        .toLowerCase()
        .includes(query);
      const matchesPosture = postureFilter === "all" || pack.posture === postureFilter;
      return matchesQuery && matchesPosture;
    });
  }, [packQuery, postureFilter]);

  const activeCatalog = catalogs[activePack.id] ?? { status: "idle" };

  const catalogRows = useMemo(() => {
    if (activeCatalog.status !== "loaded") return [];

    const query = catalogQuery.trim().toLowerCase();
    return activeCatalog.rows.filter((row) => {
      const matchesQuery = !query || row.name.toLowerCase().includes(query);
      const matchesCategory = catalogCategory === "all" || row.category === catalogCategory;
      return matchesQuery && matchesCategory;
    });
  }, [activeCatalog, catalogCategory, catalogQuery]);

  const catalogCategories = useMemo(() => {
    if (activeCatalog.status !== "loaded") return [];
    return Array.from(new Set(activeCatalog.rows.map((row) => row.category))).sort();
  }, [activeCatalog]);

  async function loadCatalog() {
    setCatalogs((current) => ({ ...current, [activePack.id]: { status: "loading" } }));
    try {
      const response = await fetch(`https://api.iconify.design/collection?prefix=${activePack.prefix}&info=1`);
      if (!response.ok) throw new Error(`HTTP ${response.status}`);

      const collection = (await response.json()) as CatalogResponse;
      setCatalogs((current) => ({
        ...current,
        [activePack.id]: {
          status: "loaded",
          total: collection.total ?? 0,
          title: collection.title ?? activePack.name,
          rows: collectionToRows(collection),
        },
      }));
      setRenderLimit(180);
    } catch (error) {
      setCatalogs((current) => ({
        ...current,
        [activePack.id]: {
          status: "error",
          message: error instanceof Error ? error.message : "Unknown error",
        },
      }));
    }
  }

  function selectPack(packId: string) {
    setActivePackId(packId);
    setCatalogCategory("all");
    setCatalogQuery("");
    setRenderLimit(180);
  }

  function selectVariant(variantId: string) {
    setActiveVariantByPack((current) => ({ ...current, [activePack.id]: variantId }));
  }

  const radius =
    appearance === "sharp"
      ? "var(--bh-radius-none)"
      : appearance === "rounded"
        ? "var(--bh-radius-full)"
        : "var(--bh-control-default)";
  const panelRadius =
    appearance === "sharp" ? "var(--bh-radius-none)" : "var(--bh-radius-lg-8)";
  const rowHeight =
    density === "compact"
      ? "calc(var(--bh-space-6xl-32) + var(--bh-space-xs-4))"
      : "calc(var(--bh-space-7xl-40) + var(--bh-space-xxs-2))";
  const previewStyle = { "--preview-icon-size": `${iconSize}px` } as CSSProperties;

  return (
    <section className="icons-page" aria-label="Icon pack explorer">
      <aside className="icons-sidebar">
        <div className="icons-sidebar__header">
          <span className="icons-mark">
            <Icon name="lucide:boxes" size={20} />
          </span>
          <div>
            <h1>Icons</h1>
            <p>Open-source pack review</p>
          </div>
        </div>

        <div className="icons-sidebar__tools">
          <input
            aria-label="Filter icon packs"
            className="icons-input"
            onChange={(event) => setPackQuery(event.target.value)}
            placeholder="Filter packs"
            type="search"
            value={packQuery}
          />
          <select
            aria-label="Filter candidates"
            className="icons-select"
            onChange={(event) => setPostureFilter(event.target.value as "all" | IconPosture)}
            value={postureFilter}
          >
            {postureOptions.map((option) => (
              <option key={option.value} value={option.value}>
                {option.label}
              </option>
            ))}
          </select>
        </div>

        <div className="icons-pack-list">
          {filteredPacks.map((pack) => (
            <button
              className={pack.id === activePack.id ? "icons-pack is-active" : "icons-pack"}
              key={pack.id}
              onClick={() => selectPack(pack.id)}
              type="button"
            >
              <span className="icons-pack__glyph">
                <Icon name={getIconName(pack, "home")} size={22} />
              </span>
              <span className="icons-pack__copy">
                <strong>{pack.name}</strong>
                <span>
                  {pack.total.toLocaleString()} icons, {pack.license}
                </span>
              </span>
            </button>
          ))}
        </div>
      </aside>

      <main className="icons-main">
        <header className="icons-topbar">
          <div>
            <h2>Icon pack explorer</h2>
            <p>
              {activePack.total.toLocaleString()} icons through Iconify prefix <code>{activePack.prefix}</code>
            </p>
          </div>

          <nav className="icons-tabs" aria-label="Icon explorer views">
            {(["evaluate", "catalog", "compare"] as ExplorerView[]).map((item) => (
              <button
                className={view === item ? "icons-tab is-active" : "icons-tab"}
                key={item}
                onClick={() => setView(item)}
                type="button"
              >
                {item[0].toUpperCase() + item.slice(1)}
              </button>
            ))}
          </nav>
        </header>

        {view === "evaluate" && (
          <div className="icons-content">
            <section className="icons-summary-grid">
              <div className="icons-panel icons-hero-panel">
                <span className="icons-hero-glyph">
                  <Icon name={getIconName(activePack, "home")} size={46} />
                </span>
                <div className="icons-hero-copy">
                  <h3>{activePack.name}</h3>
                  <p>{activePack.summary}</p>
                  <div className="icons-tags">
                    <span className="icons-tag is-warm">{activePack.posture}</span>
                    <span className="icons-tag">{activePack.license}</span>
                    {activePack.tags.map((tag) => (
                      <span className="icons-tag" key={tag}>
                        {tag}
                      </span>
                    ))}
                  </div>
                  <div className="icons-links">
                    <a href={activePack.officialUrl} rel="noreferrer" target="_blank">
                      Official
                    </a>
                    <a href={activePack.licenseUrl} rel="noreferrer" target="_blank">
                      License
                    </a>
                    <a href={`https://icon-sets.iconify.design/${activePack.prefix}/`} rel="noreferrer" target="_blank">
                      Iconify catalog
                    </a>
                  </div>
                </div>
              </div>

              <div className="icons-panel">
                <div className="icons-panel__header">
                  <h3>Fit snapshot</h3>
                </div>
                <div className="icons-score-list">
                  {[
                    ["System fit", activePack.scores.fit],
                    ["Coverage", activePack.scores.coverage],
                    ["Variant depth", activePack.scores.variants],
                    ["Dense UI clarity", activePack.scores.density],
                  ].map(([label, value]) => (
                    <div className="icons-score" key={label}>
                      <span>
                        <strong>{label}</strong>
                        <em>{value}</em>
                      </span>
                      <div>
                        <i style={{ width: `${value}%` }} />
                      </div>
                    </div>
                  ))}
                </div>
              </div>
            </section>

            <section className="icons-panel">
              <div className="icons-panel__header">
                <h3>Variants</h3>
                <span>{activeVariant.label}</span>
              </div>
              <div className="icons-variants">
                {activePack.variants.map((variant) => (
                  <button
                    className={variant.id === activeVariant.id ? "icons-variant is-active" : "icons-variant"}
                    key={variant.id}
                    onClick={() => selectVariant(variant.id)}
                    type="button"
                  >
                    {variant.label}
                  </button>
                ))}
              </div>
            </section>

            <section className="icons-panel">
              <div className="icons-panel__header">
                <h3>Icon samples</h3>
                <span>{activePack.prefix}</span>
              </div>
              <div className="icons-sample-grid">
                {iconSemantics.map(([semantic, label]) => (
                  <button className="icons-sample" key={semantic} title={getIconName(activePack, semantic)} type="button">
                    <Icon name={getIconName(activePack, semantic)} size={Math.max(iconSize, 22)} />
                    <span>{label}</span>
                  </button>
                ))}
              </div>
            </section>

            <section className="icons-component-grid">
              <div className="icons-panel">
                <div className="icons-panel__header">
                  <h3>Component controls</h3>
                </div>
                <div className="icons-controls">
                  <label>
                    <span>Icon size</span>
                    <input
                      max={30}
                      min={14}
                      onChange={(event) => setIconSize(Number(event.target.value))}
                      type="range"
                      value={iconSize}
                    />
                  </label>
                  <label>
                    <span>Appearance</span>
                    <select
                      className="icons-select"
                      onChange={(event) => setAppearance(event.target.value as Appearance)}
                      value={appearance}
                    >
                      <option value="default">Default</option>
                      <option value="rounded">Rounded</option>
                      <option value="sharp">Sharp</option>
                    </select>
                  </label>
                  <label>
                    <span>Density</span>
                    <select
                      className="icons-select"
                      onChange={(event) => setDensity(event.target.value as Density)}
                      value={density}
                    >
                      <option value="comfortable">Comfortable</option>
                      <option value="compact">Compact</option>
                    </select>
                  </label>
                </div>
              </div>

              <div className="icons-panel">
                <div className="icons-panel__header">
                  <h3>Component preview</h3>
                </div>
                <div className="icons-preview" style={previewStyle}>
                  <div className="icons-button-row">
                    <button className="preview-button is-primary" style={{ borderRadius: radius }} type="button">
                      <Icon name={getIconName(activePack, "add")} size={iconSize} />
                      Create
                    </button>
                    <button className="preview-button" style={{ borderRadius: radius }} type="button">
                      <Icon name={getIconName(activePack, "download")} size={iconSize} />
                      Export
                    </button>
                    <button className="preview-button is-danger" style={{ borderRadius: radius }} type="button">
                      <Icon name={getIconName(activePack, "trash")} size={iconSize} />
                      Delete
                    </button>
                    <button className="preview-button is-icon-only" style={{ borderRadius: radius }} type="button">
                      <Icon name={getIconName(activePack, "settings")} size={iconSize} />
                    </button>
                  </div>

                  <div className="icons-field-row">
                    <div className="icons-field" style={{ borderRadius: radius }}>
                      <Icon name={getIconName(activePack, "search")} size={iconSize} />
                      Search projects, users, invoices
                    </div>
                    <div className="icons-field is-select" style={{ borderRadius: radius }}>
                      <span>
                        <Icon name={getIconName(activePack, "filter")} size={iconSize} />
                        Status
                      </span>
                      <Icon name={getIconName(activePack, "chevron")} size={16} />
                    </div>
                  </div>

                  <div className="icons-menu-preview" style={{ borderRadius: panelRadius }}>
                    {[
                      ["home", "Dashboard", "chevron"],
                      ["users", "Customers", "24"],
                      ["bell", "Notifications", "Live"],
                    ].map(([left, label, right]) => (
                      <div className="icons-menu-row" key={label} style={{ minHeight: rowHeight }}>
                        <Icon name={getIconName(activePack, left as IconSemantic)} size={iconSize} />
                        <span>{label}</span>
                        {right === "Live" ? (
                          <em>
                            <Icon name={getIconName(activePack, "check")} size={14} />
                            Live
                          </em>
                        ) : right === "24" ? (
                          <small>24</small>
                        ) : (
                          <Icon name={getIconName(activePack, "chevron")} size={16} />
                        )}
                      </div>
                    ))}
                  </div>

                  <div className="icons-table-preview" style={{ borderRadius: panelRadius }}>
                    {[
                      ["chart", "Usage API", "Infrastructure", "92.8%", "more"],
                      ["calendar", "Billing review", "Finance", "Jun 12", "edit"],
                      ["warning", "Risk queue", "Operations", "4 open", "more"],
                    ].map(([left, name, area, value, action]) => (
                      <div className="icons-table-row" key={name} style={{ minHeight: rowHeight }}>
                        <Icon name={getIconName(activePack, left as IconSemantic)} size={iconSize} />
                        <strong>{name}</strong>
                        <span>{area}</span>
                        <span>{value}</span>
                        <Icon name={getIconName(activePack, action as IconSemantic)} size={16} />
                      </div>
                    ))}
                  </div>

                  <div className="icons-empty-preview" style={{ borderRadius: panelRadius }}>
                    <div>
                      <span style={{ borderRadius: panelRadius }}>
                        <Icon name={getIconName(activePack, "filter")} size={28} />
                      </span>
                      <h3>No matching records</h3>
                      <p>Adjust the active filters or create a saved view for this workflow.</p>
                      <button className="preview-button is-primary" style={{ borderRadius: radius }} type="button">
                        <Icon name={getIconName(activePack, "add")} size={iconSize} />
                        Saved view
                      </button>
                    </div>
                  </div>
                </div>
              </div>
            </section>
          </div>
        )}

        {view === "catalog" && (
          <div className="icons-content">
            <section className="icons-panel">
              <div className="icons-panel__header">
                <div>
                  <h3>{activePack.name} catalog</h3>
                  <span>{catalogStatusText(activeCatalog, catalogRows.length)}</span>
                </div>
              </div>
              <div className="icons-catalog-tools">
                <input
                  className="icons-input"
                  onChange={(event) => {
                    setCatalogQuery(event.target.value);
                    setRenderLimit(180);
                  }}
                  placeholder="Search icons in this pack"
                  type="search"
                  value={catalogQuery}
                />
                <select
                  className="icons-select"
                  onChange={(event) => {
                    setCatalogCategory(event.target.value);
                    setRenderLimit(180);
                  }}
                  value={catalogCategory}
                >
                  <option value="all">All categories</option>
                  {catalogCategories.map((category) => (
                    <option key={category} value={category}>
                      {category}
                    </option>
                  ))}
                </select>
                <button className="preview-button" disabled={activeCatalog.status === "loading"} onClick={loadCatalog} type="button">
                  <Icon name="lucide:download-cloud" size={18} />
                  {activeCatalog.status === "loading" ? "Loading" : "Load catalog"}
                </button>
              </div>
            </section>

            {activeCatalog.status === "error" && <div className="icons-error">Could not load catalog: {activeCatalog.message}</div>}

            <section className="icons-catalog-grid">
              {activeCatalog.status === "loaded" &&
                catalogRows.slice(0, renderLimit).map((row) => (
                  <button className="icons-catalog-card" key={`${row.category}-${row.name}`} title={`${activePack.prefix}:${row.name}`} type="button">
                    <Icon name={`${activePack.prefix}:${row.name}`} size={30} />
                    <span>{row.name}</span>
                  </button>
                ))}
            </section>

            {activeCatalog.status === "loaded" && renderLimit < catalogRows.length && (
              <button className="preview-button icons-load-more" onClick={() => setRenderLimit((current) => current + 180)} type="button">
                <Icon name="lucide:plus" size={18} />
                Show more
              </button>
            )}
          </div>
        )}

        {view === "compare" && (
          <div className="icons-content">
            <section className="icons-compare-grid">
              {iconPacks.map((pack) => (
                <article className="icons-compare-card" key={pack.id}>
                  <div>
                    <strong>{pack.name}</strong>
                    <span>{pack.license}</span>
                  </div>
                  <div className="icons-compare-icons">
                    {(["home", "search", "settings", "users", "warning"] as IconSemantic[]).map((semantic) => (
                      <span key={semantic}>
                        <Icon name={getIconName(pack, semantic)} size={22} />
                      </span>
                    ))}
                  </div>
                  <p>
                    {pack.total.toLocaleString()} icons, {pack.tags.join(", ")}
                  </p>
                </article>
              ))}
            </section>
          </div>
        )}
      </main>
    </section>
  );
}

function catalogStatusText(catalog: CatalogState, matchCount: number) {
  if (catalog.status === "idle") return "Catalog names load on demand from Iconify.";
  if (catalog.status === "loading") return "Loading the full icon name list...";
  if (catalog.status === "error") return "Catalog failed to load.";
  return `${catalog.total.toLocaleString()} icons loaded, ${matchCount.toLocaleString()} matching.`;
}
