/* sa-structure-panel.jsx — SA 캠페인·그룹·소재 "구조" 매트릭스.
   GFA는 오디언스/관심사 세그먼트 매트릭스(노출 ON·예산비중)로 표현되지만, SA는 그 패러다임이
   그대로 이식되지 않는다 — SA는 실제 계정 객체계층(campaignTp → adgroupType → adType)이고,
   층위마다 지원하는 요소(키워드매칭·확장소재·타겟·Criterion 입찰축)가 구조적으로 다르다
   (예: PLACE엔 키워드 자체가 없음, BRAND_SEARCH엔 실시간 입찰이 없음).
   이 패널은 그 구조를 SASpec(순수 레퍼런스, src/data/sa-spec.js)로 게이팅해 "이 층위에서
   실제로 무엇을 만들 수 있는가"를 보여준다 — GFA 매트릭스의 복사가 아니라 SA 고유 축.
   ★모든 요소에 confidence(documented/observed/inferred/unconfirmed) 배지 — 거짓정밀 금지(DP-4).
*/
const { useState: useSSState, useMemo: useSSMemo, useEffect: useSSEffect } = React;

const SS_CONF_TONE = { documented: 'plant', observed: 'cyan', inferred: 'signal', unconfirmed: 'alert' };
const SS_CONF_LABEL = { documented: '가능', observed: '실측관측', inferred: '구조추론', unconfirmed: '미확인' };
const SS_BID_UNIT_LABEL = { keyword: '키워드', mixed: '혼합', contract: '계약(기간)', campaign: '캠페인', 'product-or-none': '상품/없음' };
const SS_AXIS_LABEL = { gender_age: '성별×연령', gender: '성별', age: '연령', device: '디바이스', daypart: '시간대', region: '지역' };

function SSConfBadge({ c }) {
  const tone = SS_CONF_TONE[c] || 'alert';
  return <span className={'ssp-conf ssp-conf-' + tone}>{SS_CONF_LABEL[c] || c}</span>;
}

function SSGroup({ title, items, render, empty }) {
  return (
    <div className="ssp-group">
      <span className="ssp-group-t">{title} <span className="ssp-group-cnt">{items.length}</span></span>
      {items.length === 0 ? <p className="ssp-group-empty">{empty}</p> : <div className="ssp-group-items">{items.map(render)}</div>}
    </div>
  );
}

function SAStructurePanel({ brand }) {
  const SASpec = window.SASpec;
  if (!SASpec) return <div className="ssp-empty">SASpec 엔진 로드 대기.</div>;

  const campaignList = Object.keys(SASpec.CAMPAIGN_TYPES);
  const [campaignTp, setCampaignTp] = useSSState('WEB_SITE');
  const [adgroupType, setAdgroupType] = useSSState('');
  const [adType, setAdType] = useSSState('');

  const camp = SASpec.CAMPAIGN_TYPES[campaignTp];
  const adgroupOpts = camp ? camp.adgroupTypes : [];
  const adTypeOpts = (adgroupType && SASpec.ADGROUP_TYPES[adgroupType]) ? SASpec.ADGROUP_TYPES[adgroupType].adTypes : [];

  function pickCampaign(id) { setCampaignTp(id); setAdgroupType(''); setAdType(''); }
  function pickAdgroup(id) { setAdgroupType(id); setAdType(''); }

  const layer = useSSMemo(() => SASpec.matrixForLayer(campaignTp, adgroupType || undefined, adType || undefined),
    [campaignTp, adgroupType, adType]);

  // 브랜드 입찰축(daypart/region/gender_age/device) — 이 campaignTp가 실제 지원하는 축만
  // (campaignTypeGate가 diagnose-matrix.js 내부에서 이미 필터링, 여기선 재구현 없이 결과만 소비).
  // ★2026-07-18: 로컬 window.DiagnoseMatrix.build() 직접실행 → 서버 배포본(api/sa-structure.mjs)
  // 원격호출로 전환 — 첼로(progress_kit)가 부르는 것과 동일한 엔진 코드를 항상 최신 배포본으로
  // 공유하기 위함(파일 이식·양방향 동기화 대신 "소스 하나 + 원격호출"). same-origin fetch라
  // CORS/추가인증 불필요(api/sa-structure.mjs 참조). 선택이 바뀔 때만 재요청(타이핑 단위 아님).
  const [bidCells, setBidCells] = useSSState(null);
  useSSEffect(() => {
    if (!brand) { setBidCells(null); return; }
    let ignore = false;
    setBidCells(null); // 조회 중(스켈레톤) — 이전 캠페인유형 결과를 오인 표시하지 않도록 즉시 비움
    fetch('/api/sa-structure?brand_id=' + encodeURIComponent(brand) + '&campaign_type=' + encodeURIComponent(campaignTp))
      .then(r => r.json())
      .then(out => { if (!ignore) setBidCells((out && out.sa_cells) || []); })
      .catch(() => { if (!ignore) setBidCells([]); });
    return () => { ignore = true; };
  }, [brand, campaignTp]);

  const bidGroups = {};
  (bidCells || []).forEach(c => { (bidGroups[c.axis] = bidGroups[c.axis] || []).push(c); });
  const bidAxes = Object.keys(bidGroups);

  return (
    <div className="ssp">
      <div className="ssp-note">
        <span><b>SA 계정 구조</b> 관점 매트릭스 — GFA(오디언스 세그먼트)와는 별개 축입니다. 실제 SA API 계층
        (캠페인 → 광고그룹 → 소재)에서 <b>이 층위가 실제로 지원하는 요소만</b> 표시합니다. 캠페인 유형에 따라
        키워드·확장소재·타겟·입찰조정축이 구조적으로 달라집니다(예: 플레이스는 키워드가 없고, 브랜드검색은 실시간 입찰이 없습니다).</span>
      </div>

      {/* 1단 — 캠페인 유형 */}
      <div className="ssp-tier">
        <span className="ssp-tier-l">① 캠페인 유형</span>
        <div className="ssp-chips">
          {campaignList.map(id => (
            <button key={id} className="ssp-chip" data-on={campaignTp === id} onClick={() => pickCampaign(id)}>
              {SASpec.CAMPAIGN_TYPES[id].label}
            </button>
          ))}
        </div>
        {camp && <p className="ssp-tier-note">{camp.note} <SSConfBadge c={camp.confidence} /></p>}
      </div>

      {/* 2단 — 광고그룹 유형 */}
      {adgroupOpts.length > 0 && (
        <div className="ssp-tier">
          <span className="ssp-tier-l">② 광고그룹 유형 <em>(선택 안 하면 전체 합집합)</em></span>
          <div className="ssp-chips">
            <button className="ssp-chip" data-on={!adgroupType} onClick={() => pickAdgroup('')}>전체</button>
            {adgroupOpts.map(id => (
              <button key={id} className="ssp-chip" data-on={adgroupType === id} onClick={() => pickAdgroup(id)}>
                {SASpec.ADGROUP_TYPES[id] ? SASpec.ADGROUP_TYPES[id].label : id}
              </button>
            ))}
          </div>
        </div>
      )}

      {/* 3단 — 소재 유형 */}
      {adTypeOpts.length > 0 && (
        <div className="ssp-tier">
          <span className="ssp-tier-l">③ 소재 유형 <em>(선택 안 하면 전체 합집합)</em></span>
          <div className="ssp-chips">
            <button className="ssp-chip" data-on={!adType} onClick={() => setAdType('')}>전체</button>
            {adTypeOpts.map(id => (
              <button key={id} className="ssp-chip" data-on={adType === id} onClick={() => setAdType(id)}>
                {SASpec.AD_TYPES[id] ? SASpec.AD_TYPES[id].label : id}
              </button>
            ))}
          </div>
        </div>
      )}

      {layer && layer.error && <div className="ssp-error">{layer.error}</div>}

      {layer && !layer.error && (
        <>
          <div className="ssp-summary">
            <div className="ssp-sum-cell"><span>입찰 단위</span><b>{SS_BID_UNIT_LABEL[layer.biddingUnit] || layer.biddingUnit}</b></div>
            <div className="ssp-sum-cell"><span>키워드</span><b>{layer.keyword.enabled === true ? '사용' : layer.keyword.enabled === false ? '없음(자동매칭)' : String(layer.keyword.enabled)}</b></div>
            {layer.keyword.matchTypes.length > 0 && (
              <div className="ssp-sum-cell"><span>매칭타입</span><b>{layer.keyword.matchTypes.join(' · ')}</b></div>
            )}
          </div>
          {layer.note && <p className="ssp-layer-note">{layer.note}</p>}

          <div className="ssp-grid">
            <SSGroup title="확장소재" items={layer.adExtensions} empty="이 캠페인유형에 등재된 확장소재 없음"
              render={e => <span key={e.code} className="ssp-item">{e.label}{e.apiCreatable === false && <em className="ssp-noapi">API생성불가</em>}<SSConfBadge c={e.confidence} /></span>} />
            <SSGroup title="타겟" items={layer.targets} empty="적용 가능한 타겟 없음"
              render={t => <span key={t.code} className="ssp-item">{t.label}<SSConfBadge c={t.confidence} /></span>} />
            <SSGroup title="Criterion (입찰조정 축)" items={layer.criteria} empty="실시간 입찰조정 축 없음(계약형 등)"
              render={c => <span key={c.code} className="ssp-item">{c.label}<SSConfBadge c={c.confidence} /></span>} />
          </div>
        </>
      )}

      {/* 입찰축 — 브랜드 페르소나 결합 */}
      <div className="ssp-bid">
        <span className="ssp-tier-l">이 캠페인유형의 입찰 가중% (페르소나 결합)</span>
        {!brand && <p className="ssp-bid-empty">브랜드 미지정 — 구조 스펙만 표시됩니다.</p>}
        {brand && bidCells === null && <p className="ssp-bid-empty">입찰 가중% 조회 중…</p>}
        {brand && bidCells !== null && bidCells.length === 0 && (
          <p className="ssp-bid-empty">이 캠페인유형은 실시간 입찰조정 축이 없거나(계약형 등), 표본 미적재로 산출되지 않았습니다.</p>
        )}
        {bidAxes.map(ax => (
          <div key={ax} className="ssp-bid-axis">
            <span className="ssp-bid-axis-l">{SS_AXIS_LABEL[ax] || ax}</span>
            <div className="ssp-bid-cells">
              {bidGroups[ax].slice().sort((a, b) => (b.bid_weight_pct || 0) - (a.bid_weight_pct || 0)).map((c, i) => (
                <span key={i} className="ssp-bid-cell" data-strong={c.bid_weight_pct >= 120}>
                  {c.cell} <b>{c.bid_weight_pct}%</b>
                </span>
              ))}
            </div>
          </div>
        ))}
      </div>

      <style>{`
        .ssp { display: flex; flex-direction: column; gap: 12px; }
        .ssp-empty { padding: 22px; text-align: center; color: var(--text-dim); border: 1px dashed var(--border-strong); font-size: 13px; }
        .ssp-note { font-size: 12px; line-height: 1.6; color: var(--text-dim); padding: 10px 12px; background: oklch(0.66 0.15 300 / 0.07); border-left: 2px solid oklch(0.72 0.14 300); }
        .ssp-note b { color: var(--text); font-weight: 600; }

        .ssp-tier { display: flex; flex-direction: column; gap: 6px; }
        .ssp-tier-l { font-family: var(--font-mono); font-size: 10.5px; color: var(--text-mute); letter-spacing: .02em; }
        .ssp-tier-l em { font-style: normal; color: var(--text-mute); font-weight: 400; }
        .ssp-chips { display: flex; flex-wrap: wrap; gap: 6px; }
        .ssp-chip { padding: 5px 11px; background: transparent; border: 1px solid var(--border-strong); color: var(--text-dim); font-size: 11.5px; font-family: var(--font-sans); cursor: pointer; border-radius: 4px; }
        .ssp-chip[data-on="true"] { background: oklch(0.72 0.14 300 / 0.18); border-color: oklch(0.72 0.14 300); color: var(--text); font-weight: 600; }
        .ssp-tier-note { margin: 0; font-size: 10.5px; color: var(--text-mute); display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }

        .ssp-error { padding: 9px 12px; background: oklch(0.66 0.17 22 / 0.1); border: 1px solid oklch(0.66 0.17 22 / 0.4); color: oklch(0.74 0.16 22); font-size: 12px; border-radius: 5px; }

        .ssp-summary { display: flex; gap: 1px; background: var(--border); }
        .ssp-sum-cell { flex: 1; display: flex; flex-direction: column; gap: 2px; padding: 9px 10px; background: var(--ink-050, oklch(0.11 0.015 240)); }
        .ssp-sum-cell span { font-size: 10px; color: var(--text-mute); }
        .ssp-sum-cell b { font-family: var(--font-mono); font-size: 13px; color: var(--text); font-weight: 700; }
        .ssp-layer-note { margin: 0; font-size: 11px; color: var(--text-mute); line-height: 1.5; }

        .ssp-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
        @media (max-width: 720px) { .ssp-grid { grid-template-columns: 1fr; } }
        .ssp-group { padding: 10px 11px; background: oklch(0.10 0.02 240 / 0.5); border: 1px solid var(--border); border-radius: 6px; display: flex; flex-direction: column; gap: 6px; }
        .ssp-group-t { font-size: 11.5px; font-weight: 600; color: var(--text); }
        .ssp-group-cnt { font-family: var(--font-mono); font-size: 10px; color: var(--text-mute); font-weight: 400; }
        .ssp-group-empty { margin: 0; font-size: 10.5px; color: var(--text-mute); }
        .ssp-group-items { display: flex; flex-direction: column; gap: 4px; }
        .ssp-item { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: 11px; color: var(--text-dim); }
        .ssp-noapi { font-style: normal; font-size: 9px; padding: 1px 5px; border-radius: 3px; background: oklch(0.66 0.17 22 / 0.12); color: oklch(0.74 0.16 22); }

        .ssp-conf { font-family: var(--font-mono); font-size: 9px; padding: 1px 6px; border-radius: 3px; border: 1px solid; margin-left: auto; }
        .ssp-conf-plant { color: var(--plant); border-color: var(--plant); }
        .ssp-conf-cyan { color: var(--cyan); border-color: var(--cyan-dim, var(--cyan)); }
        .ssp-conf-signal { color: var(--signal); border-color: var(--signal-dim, var(--signal)); border-style: dashed; }
        .ssp-conf-alert { color: var(--alert); border-color: var(--alert); border-style: dashed; }

        .ssp-bid { padding: 11px 12px; background: oklch(0.10 0.02 240 / 0.5); border: 1px solid var(--border); border-radius: 6px; display: flex; flex-direction: column; gap: 8px; }
        .ssp-bid-empty { margin: 0; font-size: 11px; color: var(--text-mute); }
        .ssp-bid-axis { display: flex; flex-direction: column; gap: 4px; }
        .ssp-bid-axis-l { font-family: var(--font-mono); font-size: 10px; color: var(--text-mute); text-transform: uppercase; letter-spacing: .03em; }
        .ssp-bid-cells { display: flex; flex-wrap: wrap; gap: 6px; }
        .ssp-bid-cell { font-size: 11px; padding: 3px 9px; border-radius: 4px; border: 1px solid var(--border-strong); color: var(--text-dim); background: rgba(0,0,0,0.15); }
        .ssp-bid-cell b { font-family: var(--font-mono); color: var(--text); margin-left: 4px; }
        .ssp-bid-cell[data-strong="true"] { border-color: oklch(0.72 0.14 300); }
        .ssp-bid-cell[data-strong="true"] b { color: oklch(0.72 0.14 300); }
      `}</style>
    </div>
  );
}

Object.assign(window, { SAStructurePanel });
