/* 4D Geographic Matrix
   ── 4축 시각화: X (지역) · Y (연령) · Z (도달 강도, 색) · W (시간, 애니메이션)
   ── 한국 17개 광역지자체를 행으로, 9개 연령대를 열로 두고
       각 셀의 색이 도달 강도, 동시에 시간(0~24시) 슬라이더로 시간대별 변화 재생
   ── 호버 시 자세한 수치, 클릭 시 해당 셀 고정
*/

const { useState: use4DState, useMemo: use4DMemo, useEffect: use4DEffect, useRef: use4DRef } = React;

// 17 광역지자체 + 인구 비중 (2024 통계청 추정, 백분율)
const KR_REGIONS = [
  { id: 'seoul',    name: '서울특별시',     pop: 18.4, vibe: 'metro' },
  { id: 'busan',    name: '부산광역시',     pop: 6.4,  vibe: 'metro' },
  { id: 'incheon',  name: '인천광역시',     pop: 5.7,  vibe: 'metro' },
  { id: 'daegu',    name: '대구광역시',     pop: 4.6,  vibe: 'metro' },
  { id: 'daejeon',  name: '대전광역시',     pop: 2.8,  vibe: 'metro' },
  { id: 'gwangju',  name: '광주광역시',     pop: 2.8,  vibe: 'metro' },
  { id: 'ulsan',    name: '울산광역시',     pop: 2.1,  vibe: 'metro' },
  { id: 'sejong',   name: '세종특별자치시', pop: 0.7,  vibe: 'admin' },
  { id: 'gyeonggi', name: '경기도',         pop: 26.1, vibe: 'suburban' },
  { id: 'gangwon',  name: '강원특별자치도', pop: 3.0,  vibe: 'leisure' },
  { id: 'chungbuk', name: '충청북도',       pop: 3.1,  vibe: 'rural' },
  { id: 'chungnam', name: '충청남도',       pop: 4.1,  vibe: 'rural' },
  { id: 'jeonbuk',  name: '전북특별자치도', pop: 3.5,  vibe: 'rural' },
  { id: 'jeonnam',  name: '전라남도',       pop: 3.5,  vibe: 'rural' },
  { id: 'gyeongbuk',name: '경상북도',       pop: 5.0,  vibe: 'rural' },
  { id: 'gyeongnam',name: '경상남도',       pop: 6.3,  vibe: 'industrial' },
  { id: 'jeju',     name: '제주특별자치도', pop: 1.3,  vibe: 'leisure' },
];

// 지역 × 카테고리 친화도 가중치 (다른 행동 패턴)
const REGION_AFFINITY = {
  metro:      { '뷰티': 1.4, '명품': 1.6, '게임': 1.0, '여행': 1.2, '식음료': 1.1, '교육': 1.4, '금융': 1.5, '부동산': 1.4, '직업': 1.5, '자동차': 1.1 },
  suburban:   { '뷰티': 1.2, '명품': 1.0, '게임': 1.1, '여행': 1.1, '식음료': 1.2, '교육': 1.5, '금융': 1.2, '부동산': 1.5, '직업': 1.3, '자동차': 1.2, '육아': 1.4 },
  admin:      { '뷰티': 1.1, '명품': 1.0, '게임': 0.9, '여행': 0.9, '식음료': 1.0, '교육': 1.3, '금융': 1.2, '부동산': 1.0, '직업': 1.4, '자동차': 1.0, '육아': 1.3 },
  leisure:    { '뷰티': 0.9, '명품': 0.8, '게임': 0.8, '여행': 1.8, '식음료': 1.3, '교육': 0.9, '금융': 0.9, '부동산': 1.0, '직업': 0.9, '자동차': 1.0, '취미': 1.4 },
  industrial: { '뷰티': 0.9, '명품': 0.9, '게임': 1.1, '여행': 0.9, '식음료': 1.0, '교육': 1.1, '금융': 1.0, '부동산': 1.1, '직업': 1.2, '자동차': 1.4 },
  rural:      { '뷰티': 0.7, '명품': 0.6, '게임': 0.8, '여행': 1.0, '식음료': 1.2, '교육': 1.0, '금융': 0.9, '부동산': 0.8, '직업': 0.9, '자동차': 1.3, '건강': 1.3 },
};

// 시간대별 활동 변화 (0~23시, 24개 포인트)
// 지역별 + 연령별로 다르지만 여기는 평균 패턴을 1차원 인덱스로
function timeOfDayProfile(hour, ageIdx, regionVibe) {
  // 24시간 베이스 곡선 (점심·저녁 피크)
  const base = [0.15, 0.10, 0.08, 0.07, 0.08, 0.12, 0.30, 0.55, 0.70, 0.65,
                0.62, 0.68, 0.85, 0.70, 0.65, 0.70, 0.78, 0.90, 0.95, 0.92,
                0.80, 0.65, 0.45, 0.25][hour] || 0.5;
  // 연령별 시간대 편향
  let mod = 1;
  if (ageIdx <= 2 && hour >= 22) mod *= 1.4;  // young = late night
  if (ageIdx <= 2 && hour < 7)   mod *= 0.5;
  if (ageIdx >= 7 && hour >= 22) mod *= 0.5;  // senior = early sleep
  if (ageIdx >= 7 && hour < 8)   mod *= 1.3;  // senior = early morning
  if (ageIdx === 8 && hour < 6)  mod *= 1.5;
  // 지역별 (metro = 24시 활성, rural = 일찍 잠)
  if (regionVibe === 'metro' && hour >= 22) mod *= 1.2;
  if (regionVibe === 'rural' && hour >= 22) mod *= 0.6;
  return Math.min(1.5, base * mod);
}

function GeographicMatrix4D({ query, target, exposure }) {
  const result = use4DMemo(() => window.SimEngine.evalQuery(query), [query]);
  const [hour, setHour] = use4DState(20);
  const [playing, setPlaying] = use4DState(false);
  const [focusCell, setFocusCell] = use4DState(null);
  const [colorMode, setColorMode] = use4DState('reach');
  const rafRef = use4DRef(null);

  use4DEffect(() => {
    if (!playing) return;
    let last = performance.now();
    function frame(now) {
      if (now - last >= 500) { setHour(h => (h + 1) % 24); last = now; }
      rafRef.current = requestAnimationFrame(frame);
    }
    rafRef.current = requestAnimationFrame(frame);
    return () => cancelAnimationFrame(rafRef.current);
  }, [playing]);

  // === 실측 기반 계산: KR_REGION_STATS + KR_REGION_CATEGORY_INDEX + KR_REGION_HOUR_PROFILE ===
  const grid = use4DMemo(() => {
    if (!result) return null;
    const ages = window.SimEngine.AGES.filter(a => a !== '비해당');
    const allPaths = query.flatMap(g => g.leaves);
    const stats = window.KR_REGION_STATS || {};
    const catIdx = window.KR_REGION_CATEGORY_INDEX || {};
    const hourP = window.KR_REGION_HOUR_PROFILE || {};
    const vibeMap = window.KR_REGION_VIBE || {};

    // 카테고리 매칭 — 관련 인덱스 평균
    const matchedCats = Object.keys(catIdx).filter(c => allPaths.some(p => p.includes(c)));

    // 전국 통합 인구·매칭인덱스 산출 (정규화용)
    const totalPop = Object.values(stats).reduce((s, r) => s + r.totalK, 0);

    const rows = Object.entries(stats).map(([id, reg]) => {
      // ① 지역별 인구·연령 실측에서 ageDist 가져오기 (자기 자신의 연령 분포)
      const localAgeDist = reg.ages.map(p => p / 100);  // 합 = 1
      // ② 우리 query의 ageDist와 곱해서 해당 지역에 우리가 노출 가능한 연령별 인원
      //    base = 지역 인구 × (지역_ageDist[i] × query_ageDist[i])
      // ③ 카테고리×지역 친화도 (100 = 평균)
      const catBoost = matchedCats.length
        ? matchedCats.reduce((s, c) => s + ((catIdx[c]||{})[id] || 100), 0) / matchedCats.length / 100
        : 1;
      // ④ 시간대 활성도 (100 = 평균)
      const vibe = vibeMap[id] || 'metro';
      const hourMul = (hourP[vibe]?.[hour] || 100) / 100;
      // ⑤ 성별 일치도 (target.gender filter는 별도 처리)
      const femaleW = reg.female / 100;
      const genderMul = result.skew * femaleW + (1 - result.skew) * (1 - femaleW);
      // ⑥ 전국 대비 시뮬 reach 가중치
      // 인구점유 + 카테고리친화도 + 시간대활성도 + 성별일치도를 곱해서 지역 reach 분배
      const regionShareOfTotal = reg.totalK / totalPop;
      const reachShare = result.finalReach * regionShareOfTotal * catBoost * hourMul * (0.6 + genderMul * 0.8);

      const cells = ages.map((_, ai) => {
        const localAgeWeight = localAgeDist[ai];   // 지역 내 해당 연령 비중 (합 1)
        const queryAgeWeight = result.ageDist[ai] || 0;  // 시뮬에서 그 연령 도달 가중 (합 1)
        // 결합 가중치: 지역 연령 분포와 캠페인 연령 분포의 일치도
        // 단순 곱이 아닌 가중평균(0.7×지역 + 0.3×캠페인)로 산출 → 지역 인구가 결정적 영향
        const combined = localAgeWeight * 0.7 + queryAgeWeight * 0.3;
        // 9개 연령 버킷이므로 평균 가중 = 1/9, 그에 비례한 reach
        const reach = Math.round(reachShare * combined * 9);
        // CTR·CVR — 카테고리 친화도와 시간대 활성도에 영향
        const ctr = +(result.ctr * (0.78 + catBoost * 0.4) * (0.85 + hourMul * 0.3)).toFixed(2);
        const cvr = +(result.conv * (0.78 + catBoost * 0.45) * (0.85 + hourMul * 0.3)).toFixed(2);
        // 인구밀도 점유율 (per mille of regional population in that age band)
        const popInBand = reg.totalK * 10000 * localAgeWeight;
        const density = popInBand ? +(reach / popInBand * 1000).toFixed(2) : 0;
        return { reach: Math.max(0, reach), ctr, cvr, density };
      });
      return { region: { id, ...reg, vibe }, cells };
    });
    const flat = rows.flatMap(r => r.cells.map(c => c[colorMode]));
    const max = Math.max(...flat, 1);
    return { rows, ages, max };
  }, [result, query, hour, colorMode]);

  if (!result || !grid) {
    return (
      <div className="g4d-empty">
        <div style={{ fontSize: 22, color: 'var(--text-mute)' }}>◧</div>
        <div style={{ fontSize: 14, marginTop: 8 }}>4D 지오그래픽 매트릭스</div>
        <div style={{ fontSize: 12, color: 'var(--text-mute)', marginTop: 4 }}>좌측 트리에서 카테고리를 선택하세요</div>
      </div>
    );
  }

  const modeLabels = {
    reach:   { name: '도달 인원', unit: '명', tone: 'cyan' },
    cvr:     { name: '전환율',    unit: '%',  tone: 'plant' },
    ctr:     { name: '클릭률',    unit: '%',  tone: 'signal' },
    density: { name: '인구밀도 점유율', unit: '‰', tone: 'alert' },
  };
  const fc = focusCell ? grid.rows[focusCell.r]?.cells[focusCell.c] : null;
  const fr = focusCell ? grid.rows[focusCell.r]?.region : null;
  const fa = focusCell ? grid.ages[focusCell.c] : null;
  const totalActive = grid.rows.reduce((s, r) => s + r.cells.reduce((s2, c) => s2 + c.reach, 0), 0);

  return (
    <div className="g4d">
      {/* Toolbar */}
      <div className="g4d-toolbar">
        <div className="g4d-title">
          <span className="g4d-tag">4D</span>
          <strong>지오그래픽 매트릭스</strong>
          <small>X: 지역 · Y: 연령 · Z: {modeLabels[colorMode].name} · W: 시간({String(hour).padStart(2,'0')}시)</small>
        </div>
        <div className="g4d-controls">
          <div className="g4d-modes">
            {Object.entries(modeLabels).map(([k, m]) => (
              <button key={k} aria-pressed={colorMode === k} onClick={() => setColorMode(k)} data-tone={m.tone}>
                {m.name}
              </button>
            ))}
          </div>
        </div>
      </div>
      <div className="g4d-datasrc">
        <span className="label" style={{ fontSize: 10, color: 'var(--cyan)' }}>데이터 소스</span>
        <span>통계청 KOSIS 17개 광역지자체 인구·연령</span>
        <span>·</span>
        <span>데이터랩 지역 검색 인덱스</span>
        <span>·</span>
        <span>지역별 시간대 활성도 (6 vibe class)</span>
      </div>

      {/* Time axis (W) */}
      <div className="g4d-timeaxis">
        <button className="g4d-play" onClick={() => setPlaying(p => !p)}>
          {playing ? '⏸' : '▶'}
        </button>
        <input
          type="range" min={0} max={23} value={hour}
          onChange={e => { setPlaying(false); setHour(+e.target.value); }}
          className="g4d-slider"
        />
        <div className="g4d-hour-display">
          <strong>{String(hour).padStart(2,'0')}:00</strong>
          <span className="mono mute">{hourLabel(hour)}</span>
        </div>
        <div className="g4d-active">
          <span className="label" style={{ fontSize: 10 }}>현재 활성 도달</span>
          <strong>{window.SimEngine.fmtN(totalActive)}명</strong>
        </div>
      </div>

      {/* Heatmap */}
      <div className="g4d-grid-wrap">
        <div className="g4d-grid" style={{
          gridTemplateColumns: `170px repeat(${grid.ages.length}, 1fr)`,
        }}>
          <div className="g4d-corner" />
          {grid.ages.map(a => <div key={a} className="g4d-collabel">{a}</div>)}
          {grid.rows.map((row, ri) => (
            <React.Fragment key={ri}>
              <div className="g4d-rowlabel" title={`${row.region.name} (인구 ${row.region.pop}%)`}>
                <strong>{row.region.name}</strong>
                <small>{row.region.pop}%</small>
              </div>
              {row.cells.map((cell, ci) => {
                const intensity = Math.min(1, cell[colorMode] / grid.max);
                const tone = modeLabels[colorMode].tone;
                const fillHue = tone === 'cyan' ? 220 : tone === 'plant' ? 145 : tone === 'alert' ? 22 : 72;
                const fill = `oklch(${0.16 + intensity * 0.55} ${0.04 + intensity * 0.18} ${fillHue})`;
                const isFocus = focusCell && focusCell.r === ri && focusCell.c === ci;
                return (
                  <div key={ci} className={'g4d-cell' + (isFocus ? ' is-focus' : '')}
                       style={{ background: fill }}
                       onClick={() => setFocusCell(isFocus ? null : { r: ri, c: ci })}
                       title={`${row.region.name} ${grid.ages[ci]} → ${formatVal(cell[colorMode], modeLabels[colorMode].unit)}`}>
                    <span className="g4d-val" style={{
                      opacity: intensity < 0.10 ? 0.35 : intensity < 0.25 ? 0.6 : 1,
                      color: intensity < 0.18 ? 'var(--text-dim)' : 'var(--bone-100)',
                    }}>
                      {formatVal(cell[colorMode], modeLabels[colorMode].unit)}
                    </span>
                  </div>
                );
              })}
            </React.Fragment>
          ))}
        </div>
      </div>

      {/* Focus inspector */}
      {fc && fr && (
        <div className="g4d-inspector">
          <div className="g4d-ins-head">
            <strong>{fr.name}</strong> · {fa} · {String(hour).padStart(2,'0')}시
            <button onClick={() => setFocusCell(null)}>✕</button>
          </div>
          <div className="g4d-ins-stats">
            <Stat l="도달" v={window.SimEngine.fmtN(fc.reach) + '명'} tone="cyan" />
            <Stat l="클릭률" v={fc.ctr + '%'} tone="signal" />
            <Stat l="전환율" v={fc.cvr + '%'} tone="plant" />
            <Stat l="점유율" v={fc.density.toFixed(2) + '‰'} tone="alert" />
            <Stat l="지역 성향" v={vibeLabel(fr.vibe)} />
            <Stat l="인구 비중" v={fr.pop + '%'} />
          </div>
        </div>
      )}

      <style>{`
        .g4d { display: flex; flex-direction: column; gap: 12px; height: 100%; padding: 14px 18px; min-height: 0; }
        .g4d-empty { display: grid; place-items: center; height: 100%; text-align: center; color: var(--text-dim); }
        .g4d-datasrc {
          display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
          padding: 6px 12px;
          background: oklch(0.78 0.12 220 / 0.08);
          border-left: 2px solid var(--cyan);
          font-size: 11px;
          color: var(--text-dim);
          font-family: var(--font-mono);
        }
        .g4d-toolbar { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; }
        .g4d-title { display: flex; align-items: baseline; gap: 8px; }
        .g4d-title strong { font-size: 17px; font-weight: 700; }
        .g4d-title small { font-family: var(--font-mono); font-size: 11px; color: var(--text-mute); }
        .g4d-tag {
          background: var(--signal); color: var(--ink-000);
          padding: 2px 7px; font-weight: 700; font-size: 11px;
          font-family: var(--font-mono);
        }
        .g4d-modes { display: flex; }
        .g4d-modes button {
          padding: 6px 12px;
          background: var(--ink-200);
          border: 1px solid var(--border-strong);
          color: var(--text-dim);
          font-size: 12px;
          cursor: pointer;
          font-family: var(--font-sans);
        }
        .g4d-modes button + button { border-left: none; }
        .g4d-modes button:hover { color: var(--text); }
        .g4d-modes button[aria-pressed="true"][data-tone="cyan"]   { background: var(--cyan);   color: var(--ink-000); border-color: var(--cyan); }
        .g4d-modes button[aria-pressed="true"][data-tone="plant"]  { background: var(--plant);  color: var(--ink-000); border-color: var(--plant); }
        .g4d-modes button[aria-pressed="true"][data-tone="signal"] { background: var(--signal); color: var(--ink-000); border-color: var(--signal); }
        .g4d-modes button[aria-pressed="true"][data-tone="alert"]  { background: var(--alert);  color: var(--ink-000); border-color: var(--alert); }
        .g4d-timeaxis {
          display: flex; align-items: center; gap: 14px;
          padding: 10px 14px;
          background: oklch(0.10 0.02 240 / 0.6);
          border: 1px solid var(--border);
        }
        .g4d-play {
          width: 32px; height: 32px;
          background: var(--signal);
          border: none; color: var(--ink-000);
          font-size: 14px; cursor: pointer;
        }
        .g4d-slider { flex: 1; }
        .g4d-hour-display { display: flex; flex-direction: column; align-items: center; min-width: 80px; }
        .g4d-hour-display strong { font-family: var(--font-mono); font-size: 18px; color: var(--text); }
        .g4d-hour-display .mono { font-size: 10px; }
        .g4d-active { display: flex; flex-direction: column; align-items: flex-end; min-width: 120px; }
        .g4d-active strong { font-family: var(--font-mono); font-size: 16px; color: var(--cyan); }
        .g4d-grid-wrap {
          flex: 1; min-height: 0; overflow: auto;
          background: oklch(0.08 0.01 240 / 0.5);
          border: 1px solid var(--border);
          padding: 8px;
        }
        .g4d-grid {
          display: grid;
          grid-auto-rows: 32px;
          min-width: fit-content;
          gap: 1px;
          background: var(--border);
        }
        .g4d-corner { background: var(--ink-100); position: sticky; left: 0; top: 0; z-index: 5; }
        .g4d-collabel {
          background: oklch(0.13 0.015 240); color: var(--text); padding: 6px 8px;
          font-family: var(--font-mono); font-size: 11px; text-align: center;
          position: sticky; top: 0; z-index: 4;
          font-weight: 600;
        }
        .g4d-rowlabel {
          background: oklch(0.13 0.015 240); padding: 4px 10px;
          display: flex; flex-direction: column; justify-content: center;
          position: sticky; left: 0; z-index: 3;
        }
        .g4d-rowlabel strong { font-size: 12px; color: var(--text); }
        .g4d-rowlabel small { font-family: var(--font-mono); font-size: 9px; color: var(--text-mute); }
        .g4d-cell {
          display: grid; place-items: center;
          cursor: pointer;
          transition: outline 0.1s;
          background: var(--ink-100);
        }
        .g4d-cell:hover { outline: 2px solid var(--bone-100); outline-offset: -2px; z-index: 2; }
        .g4d-cell.is-focus {
          outline: 2px solid var(--signal); outline-offset: -2px; z-index: 3;
          box-shadow: 0 0 12px oklch(0.80 0.14 72 / 0.5);
        }
        .g4d-val {
          font-family: var(--font-mono);
          font-size: 10px;
          color: var(--bone-100);
          text-shadow: 0 1px 2px rgba(0,0,0,0.6);
          font-weight: 600;
        }
        .g4d-inspector {
          padding: 12px 14px;
          background: oklch(0.13 0.015 240 / 0.7);
          border: 1px solid var(--signal);
          border-left-width: 3px;
        }
        .g4d-ins-head {
          display: flex; align-items: center; gap: 8px;
          font-size: 14px; font-weight: 700;
          margin-bottom: 10px;
        }
        .g4d-ins-head button {
          margin-left: auto;
          background: none; border: none; color: var(--text-mute);
          font-size: 14px; cursor: pointer;
        }
        .g4d-ins-stats {
          display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 1px;
          background: var(--border);
        }
      `}</style>
    </div>
  );
}

function Stat({ l, v, tone }) {
  return (
    <div style={{
      padding: '8px 12px',
      background: 'oklch(0.10 0.02 240 / 0.6)',
      borderLeft: tone ? `2px solid var(--${tone})` : '2px solid var(--border-strong)',
    }}>
      <div style={{ fontSize: 10, color: 'var(--text-mute)' }}>{l}</div>
      <div style={{ fontFamily: 'var(--font-mono)', fontSize: 14, color: 'var(--text)' }}>{v}</div>
    </div>
  );
}

function hourLabel(h) {
  if (h <= 5) return '심야';
  if (h <= 11) return '아침·통근';
  if (h <= 13) return '점심';
  if (h <= 17) return '오후·업무';
  if (h <= 21) return '저녁·여가';
  return '심야 진입';
}
function formatVal(v, unit) {
  if (unit === '명') {
    if (v >= 10000) return (v/10000).toFixed(1) + '만';
    if (v >= 1000) return (v/1000).toFixed(1) + 'K';
    if (v >= 100) return Math.round(v) + '';
    return Math.round(v);
  }
  if (unit === '%') return (v).toFixed(2) + '%';
  if (unit === '‰') return (v).toFixed(2) + '‰';
  return v + unit;
}
function vibeLabel(v) {
  return {
    metro: '도심 메트로',
    suburban: '수도권 외곽',
    admin: '행정 신도시',
    leisure: '여가·관광',
    industrial: '산업·공업',
    rural: '농촌·지방',
  }[v] || v;
}

Object.assign(window, { GeographicMatrix4D });
