// Competitor keyword extraction — analyzes pinned apps' titles,
// subtitles, and descriptions to surface common words and phrases.

const { useState: useCk, useMemo: useMk, useEffect: useEk } = React;

/* ── Tokenization + frequency analysis ────────────────────── */

const STOPWORDS = new Set([
  "a","an","the","and","or","but","to","of","for","with","in","on","at","from","by","as",
  "is","are","was","were","be","been","being","have","has","had","do","does","did",
  "will","would","should","can","could","may","might","must","shall",
  "this","that","these","those","it","its","you","your","we","our","they","their",
  "i","my","me","any","all","some","no","not","so","than","then","if",
  "use","using","used","make","makes","made","get","gets","got","one","two",
  "more","most","less","also","just","only","really","such","too","very","much","many",
  "what","which","who","whom","whose","when","where","why","how",
  "into","over","under","up","down","out","about","off","through","again","further",
  "while","during","before","after","because","like","there","here","every",
  "app","apps","feature","features","new","best","top","number","day","days","time","times",
  "life","things","way","ways","work","help","helps","helping","designed",
  "free","premium","paid",
  "android","ios","ipad","iphone","watch","apple","google",
  "users","user","people","everyone","anyone","someone"
]);
const KEEP = new Set(["pro","ad","ai","kid","fun","fit","art","biz","top"]);

function tokenize(text) {
  if (!text) return [];
  return (text + "")
    .toLowerCase()
    .replace(/[''']/g, "")
    .split(/[^a-z0-9]+/)
    .filter(t => t.length > 0)
    .filter(t => (t.length >= 4 || KEEP.has(t)))
    .filter(t => !STOPWORDS.has(t))
    .filter(t => !/^\d+$/.test(t));
}

function extractWords(apps) {
  if (!apps.length) return [];

  const wordHits = new Map();

  for (const app of apps) {
    const corpus = [app.title || "", app.subtitle || "", app.description || ""].join(" ");
    const tokens = tokenize(corpus);
    const seen = new Set();
    for (const t of tokens) {
      if (seen.has(t)) continue;
      seen.add(t);
      if (!wordHits.has(t)) wordHits.set(t, new Set());
      wordHits.get(t).add(app.appId);
    }
  }

  return [...wordHits.entries()]
    .map(([term, set]) => ({ term, count: set.size, appIds: [...set] }))
    .filter(r => r.count >= 2 || (r.count >= 1 && apps.length === 1))
    .sort((a, b) => b.count - a.count);
}

/* ── Inline highlight of matched terms in text ───────────── */
function HighlightedText({ text, hits, active }) {
  if (!hits || hits.length === 0) return <span>{text}</span>;
  const sorted = [...new Set(hits)].sort((a, b) => b.length - a.length);
  const pattern = new RegExp(
    "(" + sorted.map(h => h.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|") + ")",
    "gi"
  );
  const parts = String(text).split(pattern);
  return (
    <>
      {parts.map((p, i) => {
        if (!p) return null;
        const isHit = pattern.test(p);
        pattern.lastIndex = 0;
        const isActive = active && p.toLowerCase() === active.toLowerCase();
        return isHit ? (
          <mark key={i} className={"kw-hl" + (isActive ? " kw-hl-active" : "")}>{p}</mark>
        ) : (
          <span key={i}>{p}</span>
        );
      })}
    </>
  );
}

/* ── Left pane: competitor texts with highlights ─────────── */
function CompetitorTexts({ apps, hits, active, onRemove }) {
  const [expanded, setExpanded] = useCk({});

  return (
    <div className="ck-texts">
      {apps.map(app => {
        const desc = app.description || "";
        const isLong = desc.length > 300;
        const isExpanded = expanded[app.appId];
        const shownDesc = isLong && !isExpanded ? desc.slice(0, 300) + "..." : desc;

        return (
          <div key={app.appId} className="ck-comp">
            <div className="ck-comp-head">
              <AppIcon app={app} size={40} />
              <div style={{ flex: 1, minWidth: 0 }}>
                <div className="ck-comp-title">
                  <HighlightedText text={app.title} hits={hits} active={active} />
                </div>
                {app.subtitle && (
                  <div className="ck-comp-sub">
                    <HighlightedText text={app.subtitle} hits={hits} active={active} />
                  </div>
                )}
              </div>
              {onRemove && (
                <button className="ck-comp-rm" onClick={() => onRemove(app.appId)} title="Drop from analysis">
                  <Icon name="x" size={12} />
                </button>
              )}
            </div>
            <div className="ck-comp-desc">
              <HighlightedText text={shownDesc} hits={hits} active={active} />
            </div>
            {isLong && (
              <button
                className="ck-desc-toggle"
                onClick={() => setExpanded(prev => ({ ...prev, [app.appId]: !prev[app.appId] }))}
              >
                {isExpanded ? "Show less" : "Show full description"}
              </button>
            )}
          </div>
        );
      })}
      {apps.length === 0 && (
        <div className="ck-empty-side">
          All apps removed. Add some back via the pinned tray.
        </div>
      )}
    </div>
  );
}

/* ── Right pane: word rows (local extraction) ────────────── */
function WordRows({ rows, totalApps, active, savedSet, onHover, onSave }) {
  return (
    <div className="ck-rows">
      {rows.length === 0 ? (
        <div className="ck-empty-rows">
          No shared terms found.<br/>
          <span style={{ fontFamily: "var(--mono)", fontSize: 10, letterSpacing: 1.2, textTransform: "uppercase", color: "var(--ui-ink-muted)" }}>
            try pinning more competitors
          </span>
        </div>
      ) : rows.map(r => {
        const dots = Array.from({ length: totalApps }, (_, i) => i < r.count);
        return (
          <div
            key={r.term}
            className={"ck-row" + (active === r.term ? " active" : "")}
            onMouseEnter={() => onHover(r.term)}
            onMouseLeave={() => onHover(null)}
          >
            <div className="ck-row-main">
              <div className="ck-row-term">{r.term}</div>
              <div className="ck-row-meta">
                <span className="ck-dots">
                  {dots.map((on, i) => (
                    <span key={i} className={"ck-dot" + (on ? " on" : "")} />
                  ))}
                </span>
                <span className="ck-count">{r.count}/{totalApps}</span>
              </div>
            </div>
            <button
              className={"ck-star" + (savedSet.has(r.term) ? " starred" : "")}
              onClick={() => onSave(r.term, null)}
              title={savedSet.has(r.term) ? "Saved" : "Save to keywords"}
            >
              <Icon name={savedSet.has(r.term) ? "star-fill" : "star"} size={13} />
            </button>
          </div>
        );
      })}
    </div>
  );
}

/* ── Right pane: strategic phrases (AI) ──────────────────── */
function StrategicRows({ hints, status, totalApps, active, savedSet, onHover, onSave, onRetry }) {
  if (status === "loading") {
    return (
      <div className="ck-rows" style={{ alignItems: "center", justifyContent: "center" }}>
        <div className="ck-ai-loading">
          <div className="meta-loading-spinner" style={{ width: 18, height: 18, borderWidth: 2 }} />
          <span>Analyzing competitor positioning...</span>
        </div>
      </div>
    );
  }

  if (status === "error") {
    return (
      <div className="ck-rows" style={{ alignItems: "center", justifyContent: "center" }}>
        <div className="ck-ai-error">
          AI analysis unavailable right now.
          <button onClick={onRetry} className="ck-ai-retry">Retry</button>
        </div>
      </div>
    );
  }

  if (!hints || hints.length === 0) {
    return (
      <div className="ck-rows">
        <div className="ck-empty-rows">
          Loading strategic phrases...<br/>
          <span style={{ fontFamily: "var(--mono)", fontSize: 10, letterSpacing: 1.2, textTransform: "uppercase", color: "var(--ui-ink-muted)" }}>
            AI is analyzing your competitors
          </span>
        </div>
      </div>
    );
  }

  return (
    <div className="ck-rows">
      {hints.map((h, i) => {
        const importanceDots = Array.from({ length: 3 }, (_, j) => j < h.importance);
        return (
          <div
            key={i}
            className={"ck-row" + (active === h.term ? " active" : "")}
            onMouseEnter={() => onHover(h.term)}
            onMouseLeave={() => onHover(null)}
          >
            <div className="ck-row-main">
              <div className="ck-row-term">{h.term}</div>
              <div className="ck-row-meta">
                <span className="ck-dots">
                  {importanceDots.map((on, j) => (
                    <span key={j} className={"ck-dot" + (on ? " on" : "")} />
                  ))}
                </span>
                <span className="ck-prio">{h.why}</span>
              </div>
            </div>
            <button
              className={"ck-star" + (savedSet.has(h.term) ? " starred" : "")}
              onClick={() => onSave(h.term, null)}
              title={savedSet.has(h.term) ? "Saved" : "Save to keywords"}
            >
              <Icon name={savedSet.has(h.term) ? "star-fill" : "star"} size={13} />
            </button>
          </div>
        );
      })}
    </div>
  );
}

/* ── Main modal ──────────────────────────────────────────── */
function CompetitorKeywordsModal({ open, onClose, pinnedApps, suggestions, savedKeywords, onSaveKeyword, isPro }) {
  const [tab, setTab] = useCk("strategic");
  const [active, setActive] = useCk(null);
  const [dropped, setDropped] = useCk(new Set());
  const [aiHints, setAiHints] = useCk(null);
  const [aiStatus, setAiStatus] = useCk("idle");
  const [copied, setCopied] = useCk(false);
  const [cachedFor, setCachedFor] = useCk(null);

  useEk(() => {
    if (open) {
      setDropped(new Set());
      setActive(null);
      setCopied(false);
    }
  }, [open]);

  const activeApps = useMk(
    () => pinnedApps.filter(a => !dropped.has(a.appId)),
    [pinnedApps, dropped]
  );

  const activeKey = useMk(
    () => activeApps.map(a => a.appId).sort().join(","),
    [activeApps]
  );

  const words = useMk(() => extractWords(activeApps), [activeApps]);

  // Invalidate AI cache when active apps change
  useEk(() => {
    if (cachedFor && cachedFor !== activeKey) {
      setAiHints(null);
      setAiStatus("idle");
      setCachedFor(null);
    }
  }, [activeKey]);

  // Auto-run AI when Strategic tab is active, no cached result
  useEk(() => {
    if (open && tab === "strategic" && aiStatus === "idle" && activeApps.length > 0) {
      runAi();
    }
  }, [open, tab, aiStatus, activeApps.length]);

  const currentRows = tab === "strategic" ? (aiHints || []) : words;
  const hits = useMk(() => {
    if (tab === "strategic" && aiHints) return aiHints.map(r => r.term);
    if (tab === "words") return words.map(r => r.term);
    return [];
  }, [tab, aiHints, words]);

  const savedSet = useMk(() => new Set(savedKeywords.map(k => k.term)), [savedKeywords]);

  const onSave = (term, priority) => {
    onSaveKeyword(term, priority);
  };

  const onDrop = (appId) => {
    setDropped(prev => new Set([...prev, appId]));
  };

  const onCopyAll = () => {
    try {
      const terms = tab === "strategic" && aiHints
        ? aiHints.slice(0, 30).map(r => r.term)
        : words.slice(0, 30).map(r => r.term);
      navigator.clipboard.writeText(terms.join(", "));
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    } catch (e) {}
  };

  async function runAi() {
    if (window.asoPro && !window.asoPro.isPro() && !window.asoPro.canUseResearch()) {
      window.asoPro.showPaywall();
      setAiStatus("idle");
      return;
    }
    setAiStatus("loading");
    try {
      const corpus = activeApps.map(a =>
        `APP: ${a.title}\nSUBTITLE: ${a.subtitle || "(none)"}\nDESCRIPTION: ${a.description || "(none)"}`
      ).join("\n\n---\n\n");

      const prompt = `You are an App Store Optimization expert. Analyze these ${activeApps.length} competing App Store listings. Find the most important keywords and short phrases (1-3 words, lowercase) for ASO.

Weighting rules (IMPORTANT):
- Terms from APP NAME or SUBTITLE carry 3x more ASO weight — they signal how competitors self-position for top ranks. Prioritize these.
- Terms from DESCRIPTION add context but carry less weight on their own.
- A term appearing in a title/subtitle of even one competitor is more strategic than one appearing only in multiple descriptions.

Focus on:
- Words/phrases in app names and subtitles (highest priority)
- Terms repeated across multiple listings in any field
- Category-defining terms and feature keywords
- Benefit-oriented language

Skip generic words (app, free, best, new, get, your, with, etc).

${corpus}

Return JSON: { "keywords": [{ "term": "lowercase phrase", "importance": 1-3, "why": "short reason (5-8 words max)" }] }

Return 12-16 keywords sorted by importance (3 = most important, prioritize title/subtitle terms). Output ONLY valid JSON, no prose.`;

      const res = await fetch(window.asoAPI._base + '/metadata', {
        method: 'POST',
        headers: window.asoPro ? {
          'Content-Type': 'application/json',
          'X-License-Key': window.asoPro.getLicenseKey(),
          'X-Ez-Device': window.asoPro.getDeviceId(),
          'X-Research-Consume': '1',
        } : { 'Content-Type': 'application/json' },
        body: JSON.stringify({ prompt }),
      });
      if (res.status === 402 && window.asoPro) {
        window.asoPro.showPaywall();
        throw new Error('Research limit reached');
      }
      if (!res.ok) throw new Error('LLM error');
      const data = await res.json();
      setAiHints(data.keywords || []);
      setAiStatus("done");
      if (window.asoPro && !window.asoPro.isPro()) window.asoPro.consumeResearch();
      setCachedFor(activeKey);
    } catch (e) {
      setAiStatus("error");
    }
  }

  if (!open) return null;

  const totalApps = activeApps.length;

  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="ck-modal" onClick={e => e.stopPropagation()}>
        <div className="ck-modal-head">
          <div>
            <div className="ck-eyebrow">
              <Icon name="sparkle" size={11} />
              Keyword extractor
            </div>
            <h2 className="ck-title">
              Words your <em>competitors</em> are fighting for
            </h2>
            <p className="ck-sub">
              Analyzing titles, subtitles, and full descriptions of your {totalApps} pinned
              {totalApps === 1 ? " competitor" : " competitors"} to surface strategic keywords.
            </p>
          </div>
          <button className="ah-close" onClick={onClose}><Icon name="x" size={14} /></button>
        </div>

        <div className="ck-modal-body">
          <div className="ck-left">
            <div className="ck-pane-head">
              <span className="ck-pane-label">{totalApps} competitor{totalApps === 1 ? "" : "s"} analyzed</span>
              <span className="ck-pane-hint">Highlighted terms match the active tab.</span>
            </div>
            <CompetitorTexts
              apps={activeApps}
              hits={hits}
              active={active}
              onRemove={pinnedApps.length > 2 ? onDrop : null}
            />
          </div>

          <div className="ck-right">
            <div className="ck-pane-head ck-pane-head-right">
              <div className="ck-tabs">
                <button
                  className={"ck-tab" + (tab === "strategic" ? " on" : "")}
                  onClick={() => setTab("strategic")}
                >
                  <Icon name="sparkle" size={10} />
                  Strategic <span className="ck-tab-count">{aiHints ? aiHints.length : "..."}</span>
                </button>
                <button
                  className={"ck-tab" + (tab === "words" ? " on" : "")}
                  onClick={() => setTab("words")}
                >
                  Words <span className="ck-tab-count">{words.length}</span>
                </button>
              </div>
              <button className="ck-copy-all" onClick={onCopyAll} title="Copy top 30 as comma-separated list">
                <Icon name={copied ? "check" : "copy"} size={11} />
                {copied ? "Copied" : "Copy"}
              </button>
            </div>

            {tab === "strategic" ? (
              <StrategicRows
                hints={aiHints}
                status={aiStatus}
                totalApps={totalApps}
                active={active}
                savedSet={savedSet}
                onHover={setActive}
                onSave={onSave}
                onRetry={runAi}
              />
            ) : (
              <WordRows
                rows={words}
                totalApps={totalApps}
                active={active}
                savedSet={savedSet}
                onHover={setActive}
                onSave={onSave}
              />
            )}
          </div>
        </div>

        <div className="ck-modal-foot">
          <span className="mmf-note">
            <Icon name="sparkle" size={10} />
            {tab === "strategic"
              ? "AI-powered analysis of full competitor descriptions."
              : "Local word frequency across all competitor text."}
            {" "}Star a word to save it to your keyword list.
          </span>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { CompetitorKeywordsModal, extractWords });
