// Live analyzer card: Title / Tags / Description / Personalization with real client-side analysis.

const { useState, useMemo, useEffect, useRef } = React;

const SAMPLE_TITLE = "Personalized Dog Mom Coffee Mug, Custom Pet Portrait Cup, Ceramic Mug Gift for Her, Stoneware Dog Lover Birthday Present";
const SAMPLE_TAGS = ["dog mom mug", "pet portrait", "custom dog gift", "ceramic mug", "dog lover gift", "stoneware mug", "birthday for her"];
const SAMPLE_DESC = "Personalized dog mom coffee mug with your pet's portrait, hand-painted on speckled stoneware. Free name customization. Ships in 3 business days.\n\nDetails\n– 11 oz ceramic stoneware\n– Microwave & dishwasher safe\n– Lead-free glaze, food-safe\n\nA thoughtful gift for dog moms — birthdays, holidays, or just because.";
const SAMPLE_PERSO = "Please share:\n1) Pet name (max 12 letters)\n2) Photo of your pet — clear, front-facing, daylight works best\n3) Preferred font: Script / Block / Hand-lettered\n\nLeave blank if you'd like us to surprise you with our standard layout. Proof sent in 24 hours before printing.";
const AI_LISTING_ENDPOINT = '/api/ai/etsy-listing';

function buildLimitSnapshot(title, tags, description) {
  const cleanTags = (tags || []).map(tag => String(tag || '').trim()).filter(Boolean);
  const titleChars = (title || '').length;
  const tagOverages = cleanTags
    .map((tag, index) => ({ index, tag, over: Math.max(0, tag.length - 20) }))
    .filter(item => item.over > 0);

  return {
    title: {
      value: titleChars > 140,
      reason: titleChars > 140 ? `Title is over Etsy's 140-character limit by ${titleChars - 140}.` : `Title is within Etsy's 140-character limit at ${titleChars} characters.`
    },
    tags: {
      value: cleanTags.length > 13 || tagOverages.length > 0,
      reason: cleanTags.length > 13
        ? `There are ${cleanTags.length} tags, which is ${cleanTags.length - 13} over Etsy's 13-tag limit.`
        : tagOverages.length > 0
          ? `${tagOverages.length} tag(s) exceed Etsy's 20-character tag limit.`
          : `${cleanTags.length} tags entered, and each tag is within 20 characters.`
    },
    description: {
      value: false,
      reason: description && description.trim()
        ? `No published Etsy hard cap for description length; current draft is ${(description || '').length} characters.`
        : 'No description entered yet, so there is nothing to assess for description length.'
    }
  };
}

function extractJson(text) {
  if (!text) throw new Error('Empty AI response.');

  const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
  const candidate = fenced ? fenced[1] : text.slice(text.indexOf('{'), text.lastIndexOf('}') + 1);

  if (!candidate || candidate[0] !== '{') {
    throw new Error('AI response did not contain valid JSON.');
  }

  return JSON.parse(candidate);
}

function normalizeReviewModule(module, fallbackStatus = 'fair') {
  const status = typeof module?.status === 'string' && module.status.trim()
    ? module.status.trim().toLowerCase().replace(/\s+/g, '_')
    : fallbackStatus;

  return {
    status,
    summary: typeof module?.summary === 'string' && module.summary.trim()
      ? module.summary.trim()
      : 'No summary returned for this check.',
    issues: Array.isArray(module?.issues)
      ? module.issues.map(item => String(item || '').trim()).filter(Boolean).slice(0, 3)
      : [],
    suggestions: Array.isArray(module?.suggestions)
      ? module.suggestions.map(item => String(item || '').trim()).filter(Boolean).slice(0, 3)
      : []
  };
}

function normalizeAiReview(parsed, fallback) {
  const recommended = parsed && typeof parsed === 'object' ? parsed.recommended_version || {} : {};
  const recommendedTags = Array.isArray(recommended.tags)
    ? recommended.tags.map(tag => String(tag || '').trim()).filter(Boolean).slice(0, 13)
    : [];
  const review = parsed?.listing_review || {};
  const clarityIssues = Array.isArray(parsed?.clarity_issues) ? parsed.clarity_issues.filter(Boolean) : [];
  const searchIssues = Array.isArray(parsed?.search_issues) ? parsed.search_issues.filter(Boolean) : [];
  const rewriteSuggestions = Array.isArray(parsed?.rewrite_suggestions) ? parsed.rewrite_suggestions.filter(Boolean) : [];

  return {
    over_limit: {
      title: parsed?.over_limit?.title || fallback.title,
      tags: parsed?.over_limit?.tags || fallback.tags,
      description: parsed?.over_limit?.description || fallback.description,
      summary: typeof parsed?.over_limit?.summary === 'string' && parsed.over_limit.summary.trim()
        ? parsed.over_limit.summary.trim()
        : 'This review focuses on title, tags, and description only.'
    },
    listing_review: {
      seo: normalizeReviewModule(review.seo, searchIssues.length ? 'needs_work' : 'fair'),
      clarity: normalizeReviewModule(review.clarity, clarityIssues.length ? 'needs_work' : 'fair'),
      uniqueness: normalizeReviewModule(review.uniqueness, 'fair'),
      compliance: normalizeReviewModule(review.compliance, 'clear')
    },
    issues: Array.isArray(parsed?.issues) ? parsed.issues.filter(Boolean) : [...clarityIssues, ...searchIssues],
    seo_rewrite_suggestions: Array.isArray(parsed?.seo_rewrite_suggestions)
      ? parsed.seo_rewrite_suggestions.filter(Boolean)
      : rewriteSuggestions,
    recommended_version: {
      title: typeof recommended.title === 'string' ? recommended.title.trim().slice(0, 140) : '',
      tags: recommendedTags.map(tag => tag.slice(0, 20)),
      description: typeof recommended.description === 'string' ? recommended.description.trim() : ''
    }
  };
}

async function fetchAiListingReview(payload) {
  const response = await fetch(AI_LISTING_ENDPOINT, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload)
  });

  const data = await response.json().catch(() => ({}));

  if (!response.ok) {
    throw new Error(data.error || 'AI listing review failed.');
  }

  return extractJson(data.text || '');
}

// ============================================================
// TITLE ANALYZER
// ============================================================
function analyzeTitle(text, tags) {
  const len = text.length;
  const words = text.split(/[\s,|]+/).filter(Boolean);
  const wordCount = words.length;
  const avgWord = wordCount ? (text.replace(/[^a-zA-Z]/g, '').length / wordCount).toFixed(1) : 0;
  const lower = text.toLowerCase();
  const wordsLower = lower.split(/[\s,|]+/).filter(Boolean);
  const freq = {};
  wordsLower.forEach(w => { if (w.length > 2) freq[w] = (freq[w] || 0) + 1; });
  const repeated = Object.entries(freq).filter(([w,c]) => c >= 3 && !['the','and','for','with'].includes(w));
  const upperCount = (text.match(/[A-Z]/g) || []).length;
  const upperRatio = len ? upperCount / len : 0;
  const hasEmoji = /[\u{1F300}-\u{1FAFF}\u{2600}-\u{27BF}]/u.test(text);
  const hasComma = /,/.test(text);
  const hasPipe = /\|/.test(text);
  const first40 = text.slice(0, 40);

  const tagsLower = (tags || []).map(t => t.toLowerCase().trim()).filter(Boolean);
  const overlaps = tagsLower.filter(t => t && lower.includes(t));

  const clarity = [];
  if (repeated.length === 0) clarity.push({ s: 'good', t: 'No heavily repeated words — reads naturally.' });
  else clarity.push({ s: 'warn', t: `"${repeated[0][0]}" appears ${repeated[0][1]}× — trim duplicates for clarity.` });
  if (len >= 70 && len <= 140) clarity.push({ s: 'good', t: `Title length (${len}) is comfortably within Etsy's limit.` });
  else if (len < 70) clarity.push({ s: 'warn', t: `Only ${len} chars — you may still be missing a few concrete item traits.` });
  else clarity.push({ s: 'bad', t: `Over Etsy's 140-character limit by ${len-140}.` });
  if (avgWord >= 3.5 && avgWord <= 7) clarity.push({ s: 'good', t: `Average word length ${avgWord} — comfortable scan rhythm.` });
  else clarity.push({ s: 'warn', t: `Average word length ${avgWord} — may feel choppy.` });
  if (upperRatio < 0.35) clarity.push({ s: 'good', t: 'Capitalization is balanced and not shouty.' });
  else clarity.push({ s: 'warn', t: 'Heavy uppercase reads as spam to shoppers.' });
  if (hasComma || hasPipe) clarity.push({ s: 'good', t: `Consistent delimiter (${hasPipe ? 'pipes' : 'commas'}) groups keyword phrases.` });
  else clarity.push({ s: 'warn', t: 'No delimiters — consider commas to separate keyword phrases.' });
  if (!hasEmoji) clarity.push({ s: 'good', t: 'No decorative symbols — the title stays easy to scan.' });
  else clarity.push({ s: 'warn', t: 'Decorative symbols can make the title harder to scan.' });

  const seo = [];
  if (first40.split(' ').filter(Boolean).length >= 4)
    seo.push({ s: 'good', t: 'Core item wording appears early, which helps fast scanning in narrow result layouts.' });
  else
    seo.push({ s: 'warn', t: 'Move the clearest item phrase closer to the front.' });
  if (overlaps.length >= 1)
    seo.push({ s: 'good', t: `Title shares ${overlaps.length} tag phrase(s) — the listing stays consistent.` });
  else if (tagsLower.length)
    seo.push({ s: 'warn', t: 'None of your tag phrases appear in the title — make sure the listing still feels cohesive.' });
  if (wordCount <= 15)
    seo.push({ s: 'good', t: `${wordCount} words — aligned with Etsy's newer guidance to consider concise titles.` });
  else
    seo.push({ s: 'warn', t: `${wordCount} words — still valid, but check that every phrase earns its place.` });
  const uniqRatio = new Set(wordsLower).size / Math.max(wordCount,1);
  if (uniqRatio > 0.75) seo.push({ s: 'good', t: 'Strong word variety — broadens search match.' });
  else seo.push({ s: 'warn', t: 'Word variety is low — swap synonyms in.' });
  if (/gift|present|him|her|mom|dad|birthday/i.test(text))
    seo.push({ s: 'good', t: 'Recipient or occasion wording is present where it looks relevant.' });
  else
    seo.push({ s: 'warn', t: 'If this is genuinely a giftable item, consider adding a recipient or occasion term.' });

  const clarityStatus = clarity.some(r => r.s === 'bad') ? 'bad' : clarity.some(r => r.s === 'warn') ? 'warn' : 'good';
  const seoStatus = seo.some(r => r.s === 'bad') ? 'bad' : seo.some(r => r.s === 'warn') ? 'warn' : 'good';

  return { len, wordCount, avgWord, clarity, seo, clarityStatus, seoStatus };
}

function TitleAnalyzer({ text, setText, tags, setTags, desc, setDesc }) {
  const a = useMemo(() => analyzeTitle(text, tags), [text, tags]);
  const [openClarity, setOpenClarity] = useState(true);
  const [openSeo, setOpenSeo] = useState(true);
  const [liveReviewVisible, setLiveReviewVisible] = useState(false);
  const [aiLoading, setAiLoading] = useState(false);
  const [aiError, setAiError] = useState('');
  const [aiReview, setAiReview] = useState(null);
  const [showRecommended, setShowRecommended] = useState(false);

  const counterStatus = a.len > 140 ? 'bad' : a.len > 130 ? 'warn' : a.len < 60 ? 'warn' : 'good';
  const barPct = Math.min(100, (a.len / 140) * 100);

  const aiLimitSnapshot = useMemo(() => buildLimitSnapshot(text, tags, desc), [text, tags, desc]);

  async function runAiReview() {
    setAiLoading(true);
    setAiError('');

    try {
      const parsed = await fetchAiListingReview({
        title: text,
        tags,
        description: desc
      });
      setAiReview(normalizeAiReview(parsed, aiLimitSnapshot));
      setShowRecommended(false);
    } catch (error) {
      setAiError(error instanceof Error ? error.message : 'AI listing review failed.');
    } finally {
      setAiLoading(false);
    }
  }

  return (
    <div>
      <div className="counter-row">
        <span className="counter-label">Etsy title — up to 140 characters</span>
        <span className={`counter ${counterStatus}`}>
          <span className="num">{a.len}</span> / 140 chars · <span>{a.wordCount} words</span>
        </span>
      </div>
      <textarea
        className="input"
        value={text}
        maxLength={200}
        onChange={(e) => setText(e.target.value)}
        placeholder="Paste your Etsy title here…"
      />
      <div className={`bar ${counterStatus}`}>
        <span style={{ width: `${barPct}%` }} />
      </div>

      <a className="ai-trigger workspace-trigger" href="../listing-workspace.html">
        <span className="workspace-trigger-copy">
          <strong>See if your listing needs optimization</strong>
          <small>Diagnose your title, tags, and description, then improve the full listing in the workspace.</small>
        </span>
        <span className="workspace-cta">Open listing workspace <Icon.arrow /></span>
      </a>

      {liveReviewVisible && (
        <>
          <div className="analysis-intro">
            <span className="mini-badge">Live review</span>
            <p>These checks update as you type. Green rows mean the draft is within documented limits or is following the cleaner guidance path; warning rows show where the draft can be tightened.</p>
          </div>

          <div className="analysis">
            <AGroup
              name="Clarity"
              status={a.clarityStatus}
              summary={`${a.clarity.filter(r=>r.s==='good').length}/${a.clarity.length} checks passing`}
              open={openClarity}
              onToggle={() => setOpenClarity(!openClarity)}
              rows={a.clarity}
            />
            <AGroup
              name="SEO"
              status={a.seoStatus}
              summary={`${a.seo.filter(r=>r.s==='good').length}/${a.seo.length} checks passing`}
              open={openSeo}
              onToggle={() => setOpenSeo(!openSeo)}
              rows={a.seo}
            />
          </div>

          {!aiReview && (
            <>
              <button className="ai-trigger" style={{ marginTop: 14 }} onClick={runAiReview} disabled={aiLoading}>
                <Icon.sparkle /> {aiLoading ? 'Generating…' : 'Generate optimized listing'} <span className="ai-tag">AI</span>
              </button>
              {aiError && (
                <div style={{ marginTop: 8, fontSize: 13, color: 'var(--red, #c0392b)', padding: '8px 12px', background: 'rgba(192,57,43,0.07)', borderRadius: 8 }}>
                  {aiError}
                </div>
              )}
            </>
          )}
        </>
      )}

      {aiReview && (
        <div className="improve">
          <div className="improve-head">
            <div className="h"><Icon.sparkle className="sparkle" /> AI listing review</div>
            <span style={{ fontSize: 12, color: 'var(--fg-3)' }} className="mono">title + tags + description</span>
          </div>

          <div className="analysis" style={{ marginTop: 14 }}>
            <div className="analysis-group">
              <div className="ag-head">
                <div className="lhs">
                  <span className={`status-dot status-${aiReview.over_limit.title.value || aiReview.over_limit.tags.value ? 'bad' : 'good'}`} />
                  <span className="name">Limit check</span>
                  <span className="summary">{aiReview.over_limit.summary}</span>
                </div>
              </div>
              <div className="ag-list">
                <div className={`ag-row ${aiReview.over_limit.title.value ? 'bad' : 'good'}`}><span className="d" /><span>Title: {aiReview.over_limit.title.reason}</span></div>
                <div className={`ag-row ${aiReview.over_limit.tags.value ? 'bad' : 'good'}`}><span className="d" /><span>Tags: {aiReview.over_limit.tags.reason}</span></div>
                <div className={`ag-row ${aiReview.over_limit.description.value ? 'bad' : 'good'}`}><span className="d" /><span>Description: {aiReview.over_limit.description.reason}</span></div>
              </div>
            </div>

            <ReviewModule name="SEO" module={aiReview.listing_review.seo} />
            <ReviewModule name="Clarity" module={aiReview.listing_review.clarity} />
            <ReviewModule name="Unique appeal" module={aiReview.listing_review.uniqueness} />
            <ReviewModule name="Compliance" module={aiReview.listing_review.compliance} />
          </div>

          {!showRecommended ? (
            <button className="ai-trigger" style={{ marginTop: 14 }} onClick={() => setShowRecommended(true)}>
              <Icon.sparkle /> Generate optimized listing <span className="ai-tag">AI</span>
            </button>
          ) : (
            <div className="imp-output" style={{ marginTop: 14 }}>
              <div className="imp-label">Recommended version</div>
              <div className="imp-text" style={{ whiteSpace: 'normal' }}>
                <strong>Title</strong><br />
                {aiReview.recommended_version.title || 'No recommended title returned.'}
                <br /><br />
                <strong>Tags</strong><br />
                {aiReview.recommended_version.tags.length ? aiReview.recommended_version.tags.join(' · ') : 'No recommended tags returned.'}
                <br /><br />
                <strong>Description</strong><br />
                <span style={{ whiteSpace: 'pre-wrap' }}>
                  {aiReview.recommended_version.description || 'No recommended description returned.'}
                </span>
              </div>
              <div className="imp-meta" style={{ alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
                <span className="ch">{(aiReview.recommended_version.title || '').length} / 140 title chars</span>
                <span>·</span>
                <span>{aiReview.recommended_version.tags.length} suggested tags</span>
                <button
                  className="btn btn-sm btn-accent"
                  style={{ marginLeft: 'auto' }}
                  onClick={() => {
                    if (aiReview.recommended_version.title) setText(aiReview.recommended_version.title);
                    if (aiReview.recommended_version.tags.length) setTags(aiReview.recommended_version.tags);
                    if (aiReview.recommended_version.description) setDesc(aiReview.recommended_version.description);
                  }}
                >
                  <Icon.check /> Apply all
                </button>
                <button
                  className="btn btn-sm"
                  onClick={() => {
                    if (aiReview.recommended_version.title) setText(aiReview.recommended_version.title);
                  }}
                >
                  Apply title
                </button>
                <button
                  className="btn btn-sm"
                  onClick={() => {
                    if (aiReview.recommended_version.tags.length) setTags(aiReview.recommended_version.tags);
                  }}
                >
                  Apply tags
                </button>
                <button
                  className="btn btn-sm"
                  onClick={() => {
                    if (aiReview.recommended_version.description) setDesc(aiReview.recommended_version.description);
                  }}
                >
                  Apply description
                </button>
              </div>
            </div>
          )}
        </div>
      )}
    </div>
  );
}

function AGroup({ name, status, summary, open, onToggle, rows }) {
  return (
    <div className="analysis-group">
      <div className="ag-head" onClick={onToggle}>
        <div className="lhs">
          <span className={`status-dot status-${status}`} />
          <span className="name">{name}</span>
          <span className="summary">{summary}</span>
        </div>
        <span className="toggle">{open ? 'Hide details' : 'Show details'} {open ? '▴' : '▾'}</span>
      </div>
      {open && (
        <div className="ag-list">
          {rows.map((r, i) => (
            <div key={i} className={`ag-row ${r.s}`}>
              <span className="d" /> <span>{r.t}</span>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

function ReviewModule({ name, module }) {
  const normalizedStatus = module?.status === 'needs_work'
    ? 'bad'
    : module?.status === 'fair' || module?.status === 'review'
      ? 'warn'
      : 'good';
  const rows = [
    ...(module?.issues?.length ? module.issues.map(t => ({ s: normalizedStatus === 'good' ? 'warn' : normalizedStatus, t })) : []),
    ...(module?.suggestions?.length ? module.suggestions.map(t => ({ s: 'good', t: `Fix: ${t}` })) : [])
  ];
  const fallback = normalizedStatus === 'good'
    ? 'No major issue found in this module.'
    : 'No detailed issue returned for this module.';

  return (
    <div className="analysis-group">
      <div className="ag-head">
        <div className="lhs">
          <span className={`status-dot status-${normalizedStatus}`} />
          <span className="name">{name}</span>
          <span className="summary">{module?.summary || fallback}</span>
        </div>
      </div>
      <div className="ag-list">
        {(rows.length ? rows : [{ s: normalizedStatus, t: fallback }]).map((row, index) => (
          <div key={index} className={`ag-row ${row.s}`}>
            <span className="d" /> <span>{row.t}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

// ============================================================
// TAGS ANALYZER
// ============================================================
function TagsAnalyzer({ tags, setTags, title }) {
  const [draft, setDraft] = useState('');
  const [showAI, setShowAI] = useState(false);
  const [analyzed, setAnalyzed] = useState(false);
  const inputRef = useRef(null);

  const addTag = (v) => {
    const t = v.trim().slice(0, 20);
    if (!t) return;
    if (tags.length >= 13) return;
    setTags([...tags, t]);
    setDraft('');
  };

  const remove = (i) => setTags(tags.filter((_,j)=>j!==i));

  const total = tags.reduce((s,t)=>s+t.length, 0);
  const dupes = new Set();
  tags.forEach((t,i)=>{ const k=t.toLowerCase(); if (tags.findIndex(x=>x.toLowerCase()===k)!==i) dupes.add(k); });

  // detect tags that duplicate title's exact words
  const titleLower = (title || '').toLowerCase();
  const titleOverlap = tags.filter(t => titleLower.includes(t.toLowerCase()));

  const suggestions = ['vegan leather', 'gift for her', 'eco friendly', 'small batch', 'hand painted', 'minimalist gift'];
  const sugUnused = suggestions.filter(s => !tags.find(t => t.toLowerCase() === s));

  return (
    <div className="tag-editor">
      <div className="counter-row">
        <span className="counter-label">Etsy tags — 13 max · 20 chars each</span>
        <span className={`counter ${tags.length>13?'bad':tags.length>=10?'good':'warn'}`}>
          <span className="num">{tags.length}</span> / 13 tags · <span>{total} chars used</span>
        </span>
      </div>
      <div className="tag-input-row">
        <Icon.hash />
        <input
          ref={inputRef}
          value={draft}
          maxLength={20}
          placeholder={tags.length>=13 ? 'Max 13 tags reached' : 'Type a tag and press Enter…'}
          disabled={tags.length>=13}
          onChange={(e)=>setDraft(e.target.value)}
          onKeyDown={(e)=> {
            if (e.key === 'Enter' || e.key === ',') { e.preventDefault(); addTag(draft); }
            if (e.key === 'Backspace' && !draft && tags.length) { setTags(tags.slice(0,-1)); }
          }}
        />
        <span className="counter mono" style={{ fontSize: 11 }}>{draft.length}/20</span>
        <button className="btn btn-sm btn-accent" onClick={()=>addTag(draft)} disabled={!draft.trim()}>
          <Icon.plus /> Add
        </button>
      </div>
      <div className="tag-chips">
        {tags.map((t,i) => {
          const long = t.length >= 18;
          const dup = dupes.has(t.toLowerCase());
          const cls = dup ? 'tag-chip bad' : long ? 'tag-chip warn' : 'tag-chip';
          return (
            <span key={i} className={cls}>
              <span>{t}</span>
              <span className="count mono">{t.length}</span>
              <button className="x" onClick={()=>remove(i)} aria-label="Remove tag"><Icon.x /></button>
            </span>
          );
        })}
        {Array.from({ length: Math.max(0, 13 - tags.length) }).map((_,i)=>(
          <span key={'p'+i} className="tag-chip" style={{ background:'transparent', borderStyle:'dashed', color:'var(--fg-4)' }}>
            slot {tags.length + i + 1}
          </span>
        ))}
      </div>

      <a className="ai-trigger workspace-trigger" href="../listing-workspace.html">
        <span className="workspace-trigger-copy">
          <strong>See if your listing needs optimization</strong>
          <small>Diagnose your title, tags, and description, then improve the full listing in the workspace.</small>
        </span>
        <span className="workspace-cta">Open listing workspace <Icon.arrow /></span>
      </a>

    </div>
  );
}

// ============================================================
// DESCRIPTION ANALYZER
// ============================================================
function DescAnalyzer({ text, setText }) {
  const [analyzed, setAnalyzed] = useState(false);
  const len = text.length;
  const status = len < 120 ? 'warn' : 'good';
  const snippet = text.slice(0, 180);
  const firstLineLen = (text.split('\n')[0] || '').length;
  const hasBullets = /(\n[-–•*])/.test(text);
  const checks = [
    { s: firstLineLen >= 90 ? 'good' : 'warn',
      t: firstLineLen >= 90
        ? `Opening line is ${firstLineLen} chars — enough room to explain the item clearly.`
        : `Opening line is ${firstLineLen} chars — make it more specific before the buyer starts scrolling.` },
    { s: hasBullets ? 'good' : 'warn',
      t: hasBullets ? 'Includes scannable bullets — great for buyers who skim.' : 'No bullets detected — add a "Details" list under the hook.' },
    { s: /\d/.test(text) ? 'good' : 'warn',
      t: /\d/.test(text) ? 'Concrete numbers present (dimensions, qty, days).' : 'Add numbers — sizes, oz, days — they convert skimmers.' },
    { s: len >= 350 ? 'good' : 'warn',
      t: len >= 350 ? `${len} chars — enough room for substance without relying on a hard cap.` : `${len} chars — add a few more specifics so the buyer doesn't need to guess.` },
  ];
  const groupStatus = checks.some(c=>c.s==='bad') ? 'bad' : checks.some(c=>c.s==='warn') ? 'warn' : 'good';

  return (
    <div>
      <div className="counter-row">
        <span className="counter-label">Description draft length · Google snippets vary, so the opening lines matter most</span>
        <span className={`counter ${status}`}>
          <span className="num">{len.toLocaleString()}</span> chars
        </span>
      </div>
      <textarea
        className="input tall"
        value={text}
        onChange={(e)=>setText(e.target.value)}
        placeholder="Paste your Etsy description here…"
      />

      <a className="ai-trigger workspace-trigger" href="../listing-workspace.html">
        <span className="workspace-trigger-copy">
          <strong>See if your listing needs optimization</strong>
          <small>Diagnose your title, tags, and description, then improve the full listing in the workspace.</small>
        </span>
        <span className="workspace-cta">Open listing workspace <Icon.arrow /></span>
      </a>

      {analyzed && (
        <>
          <div className="preview-card" style={{ marginTop: 14 }}>
            <div className="ph"><span className="pdot" /> <Icon.scan /> Opening excerpt · preview only</div>
            <div className="body">
              {snippet}{text.length > 180 ? '…' : ''}
            </div>
          </div>

          <div className="analysis">
            <div className="analysis-group">
              <div className="ag-head">
                <div className="lhs">
                  <span className={`status-dot status-${groupStatus}`} />
                  <span className="name">Description structure</span>
                  <span className="summary">{checks.filter(c=>c.s==='good').length}/{checks.length} checks passing</span>
                </div>
              </div>
              <div className="ag-list">
                {checks.map((c,i)=>(<div key={i} className={`ag-row ${c.s}`}><span className="d" /><span>{c.t}</span></div>))}
              </div>
            </div>
          </div>
        </>
      )}
    </div>
  );
}

// ============================================================
// PERSONALIZATION ANALYZER
// ============================================================
function PersonalizationAnalyzer({ text, setText }) {
  const [showAI, setShowAI] = useState(false);
  const [analyzed, setAnalyzed] = useState(false);
  // Current Etsy text-box personalization fields can be set between 1 and 1,024 chars.
  const len = text.length;
  const status = len > 1024 ? 'bad' : len < 40 ? 'warn' : 'good';
  const barPct = Math.min(100, (len / 1024) * 100);

  const hasQuestion = /\?|please|share|list|provide|enter|type|spell|specify/i.test(text);
  const hasExample = /e\.g\.|example|sample|like|such as|e\.x\.|max|up to/i.test(text);
  const hasLineBreaks = text.split('\n').length >= 2;
  const hasNumbered = /\n?\s*\d[\.\)]/.test(text);

  const checks = [
    { s: hasQuestion ? 'good' : 'warn',
      t: hasQuestion ? 'Reads as a clear ask — buyers know what to type.' : 'Phrase as a direct ask: "Please share your pet name…"' },
    { s: hasExample ? 'good' : 'warn',
      t: hasExample ? 'Includes examples / limits — reduces back-and-forth messages.' : 'Add an example or character cap so buyers don\'t over-write.' },
    { s: hasNumbered || hasLineBreaks ? 'good' : 'warn',
      t: hasNumbered ? 'Numbered list — easy for buyers to fill out item-by-item.' : 'Use a numbered list when you need more than one piece of info.' },
    { s: len <= 1024 ? 'good' : 'bad',
      t: len <= 1024 ? `${len} / 1,024 — within Etsy's text-box limit.` : `Over Etsy's 1,024-character text-box limit by ${len-1024}.` },
  ];
  const groupStatus = checks.some(c=>c.s==='bad') ? 'bad' : checks.some(c=>c.s==='warn') ? 'warn' : 'good';

  return (
    <div>
      <div className="counter-row">
        <span className="counter-label">Personalization text box — Etsy lets sellers set a 1-1,024-character limit</span>
        <span className={`counter ${status}`}>
          <span className="num">{len}</span> / 1,024 chars
        </span>
      </div>
      <textarea
        className="input"
        value={text}
        onChange={(e)=>setText(e.target.value)}
        placeholder="Tell the buyer exactly what you need…"
        style={{ minHeight: 140 }}
      />
      <div className={`bar ${status}`}>
        <span style={{ width: `${barPct}%` }} />
      </div>

      <a className="ai-trigger workspace-trigger" href="../listing-workspace.html">
        <span className="workspace-trigger-copy">
          <strong>See if your listing needs optimization</strong>
          <small>Diagnose your title, tags, and description, then improve the full listing in the workspace.</small>
        </span>
        <span className="workspace-cta">Open listing workspace <Icon.arrow /></span>
      </a>

      {analyzed && (
        <>
          <div className="preview-card" style={{ marginTop: 14 }}>
            <div className="ph"><span className="pdot" /> <Icon.gift /> Buyer sees · personalization box</div>
            <div className="body" style={{ whiteSpace: 'pre-wrap' }}>{text || <em style={{color:'var(--fg-4)'}}>Empty — buyer will see the field with no guidance.</em>}</div>
          </div>

          <div className="analysis">
            <div className="analysis-group">
              <div className="ag-head">
                <div className="lhs">
                  <span className={`status-dot status-${groupStatus}`} />
                  <span className="name">Instruction clarity</span>
                  <span className="summary">{checks.filter(c=>c.s==='good').length}/{checks.length} checks passing</span>
                </div>
              </div>
              <div className="ag-list">
                {checks.map((c,i)=>(<div key={i} className={`ag-row ${c.s}`}><span className="d" /><span>{c.t}</span></div>))}
              </div>
            </div>
          </div>

          {!showAI ? (
            <button className="ai-trigger" onClick={()=>setShowAI(true)}>
              <Icon.sparkle /> Insert a template <span className="ai-tag">AI</span>
            </button>
          ) : (
            <div className="improve">
              <button className="ai-close" onClick={()=>setShowAI(false)} aria-label="Close templates">
                <Icon.x />
              </button>
              <div className="improve-head">
                <div className="h"><Icon.sparkle className="sparkle" /> Quick templates</div>
                <span className="mono" style={{ fontSize:12, color:'var(--fg-3)' }}>copy-ready</span>
              </div>
              <div className="improve-buttons">
                <button className="imp-btn" onClick={()=>setText("Please share:\n1) Name (max 12 letters)\n2) Color preference\n3) Any special instructions\n\nLeave blank for our default. Proof sent within 24h.")}>
                  <Icon.copy className="ic" /> Personalized item template
                </button>
                <button className="imp-btn" onClick={()=>setText("Upload your photo (clear, daylight, front-facing) and tell us the pet's name. Max 15 letters. We'll send a digital proof in 24 hours.")}>
                  <Icon.copy className="ic" /> Pet portrait template
                </button>
                <button className="imp-btn" onClick={()=>setText("Enter the date you'd like printed (e.g. 06/14/2026) and the names (max 20 letters each). Leave blank to skip.")}>
                  <Icon.copy className="ic" /> Wedding / event template
                </button>
              </div>
            </div>
          )}
        </>
      )}
    </div>
  );
}

window.TitleAnalyzer = TitleAnalyzer;
window.TagsAnalyzer = TagsAnalyzer;
window.DescAnalyzer = DescAnalyzer;
window.PersonalizationAnalyzer = PersonalizationAnalyzer;
window.SAMPLE_TITLE = SAMPLE_TITLE;
window.SAMPLE_TAGS = SAMPLE_TAGS;
window.SAMPLE_DESC = SAMPLE_DESC;
window.SAMPLE_PERSO = SAMPLE_PERSO;
