// KPI Progress view — targets vs. actuals by channel/segment
// Reads kpi_targets + aggregates sales_core by channel_group

function KpiView({ lang, perms }) {
  const [year, setYear] = React.useState(2026);
  // v3.3: KpiView는 캐시 동기 적용 X — actuals/kpi state 빌드 흐름과 충돌 발견되어 보류.
  // 다른 view들은 캐시 hit 즉시 표시. KPI만 loading 거침.
  const [loading, setLoading] = React.useState(true);
  const [kpi, setKpi]     = React.useState(null);
  const [actuals, setActuals] = React.useState(null);
  const [err, setErr]     = React.useState(null);
  // Progressive render: summary cards paint first, chart + tracking table
  // mount after a small delay so the user sees something within ~1s.
  const [showSecondary, setShowSecondary] = React.useState(false);
  // 4번째 summary 카드: 달성률 ↔ 부족률 자동 번갈아 토글 (3.5초 간격)
  const [showShortage, setShowShortage] = React.useState(false);
  const barRef  = React.useRef(null);
  const chartRef = React.useRef(null);

  const t = lang === 'en' ? KT_EN : KT_KO;

  React.useEffect(() => {
    let aborted = false;
    (async () => {
      setLoading(true);
      setShowSecondary(false);
      setErr(null);
      try {
        const [targets, rows] = await Promise.all([
          SALES_DB.fetchKpiTargets(year),
          SALES_DB.fetchAllSalesData(),
        ]);
        if (aborted) return;
        setKpi(buildKpiMap(targets));
        setActuals(buildActuals(rows, year));
      } catch (e) {
        if (!aborted) setErr(e?.message || String(e));
      } finally {
        if (!aborted) setLoading(false);
      }
    })();
    return () => { aborted = true; };
  }, [year]);

  // Defer the heavy chart + tracking table by ~250ms so the summary cards
  // paint first on slow networks.
  React.useEffect(() => {
    if (loading) return;
    const id = setTimeout(() => setShowSecondary(true), 250);
    return () => clearTimeout(id);
  }, [loading]);

  // 달성률 ↔ 부족률 토글 — loading 끝난 뒤 3.5초 간격으로 번갈아.
  React.useEffect(() => {
    if (loading) return;
    const id = setInterval(() => setShowShortage(s => !s), 3500);
    return () => clearInterval(id);
  }, [loading]);

  // Channel bar chart — only constructs when the secondary block is mounted.
  // 디자인: 한 막대 = 채널별 목표 높이. 아래는 실적(주황 실선), 위는 부족분
  // (점선 빨강 투명) — stacked. 합치면 목표 = 두 segment의 합.
  // 부족분 막대 위에 금액 라벨을 inline plugin으로 항상 표시.
  React.useEffect(() => {
    if (!kpi || !actuals || !barRef.current || !showSecondary) return;

    if (chartRef.current) { chartRef.current.destroy(); chartRef.current = null; }

    const channels = ['US', 'ROW', 'KR'];
    const fgMuted  = getComputedStyle(document.documentElement).getPropertyValue('--fg-muted').trim();
    const gridC    = 'rgba(128,128,128,0.12)';
    const accent   = getComputedStyle(document.documentElement).getPropertyValue('--accent').trim();

    // 모든 값은 억 단위 (1e7로 나눠 소수점 1자리). 음수 방지: 실적이 목표 초과면
    // 부족분은 0. (초과분 시각화는 별도 작업으로 미룸.)
    const targetData   = channels.map(ch => Math.round((kpi[ch]?.revenue || 0) / 1e7) / 10);
    const actualData   = channels.map(ch => Math.round((actuals.byChannel[ch] || 0) / 1e7) / 10);
    const shortageData = channels.map((_, i) => Math.max(0, +(targetData[i] - actualData[i]).toFixed(1)));

    // 부족분 막대 안에 두 줄 라벨을 그리는 inline plugin:
    //   1) 부족 총량 (예: "102.3억")
    //   2) 잔여 월평균 (예: "월 12.8억") — 부족분 ÷ 잔여월수
    // 막대 높이가 작으면 한 줄(총량)만 표시.
    // afterDatasetsDraw로 모든 막대 그려진 후 캔버스 직접 그리기.
    const monthsLeftForChart = Math.max(1, 12 - (new Date().getMonth() + 1));
    const shortageLabelPlugin = {
      id: 'shortageLabels',
      afterDatasetsDraw(chart) {
        const ctxd = chart.ctx;
        const meta = chart.getDatasetMeta(1);  // dataset index 1 = 부족분
        if (!meta || !meta.data) return;
        const fontStack = (getComputedStyle(document.documentElement).getPropertyValue('--font-sans') || 'sans-serif').trim();
        meta.data.forEach((bar, i) => {
          const value = chart.data.datasets[1].data[i];
          if (value <= 0 || !bar) return;
          const paceVal = +(value / monthsLeftForChart).toFixed(1);
          ctxd.save();
          ctxd.textAlign = 'center';
          ctxd.textBaseline = 'middle';
          const yMid = (bar.y + bar.base) / 2;
          const barHeight = bar.base - bar.y;
          if (barHeight >= 36) {
            // 두 줄: 총량 + 월 페이스
            ctxd.fillStyle = '#FF453A';
            ctxd.font = '600 12px ' + fontStack;
            ctxd.fillText(value + '억', bar.x, yMid - 8);
            ctxd.fillStyle = 'rgba(255,69,58,0.75)';
            ctxd.font = '500 10px ' + fontStack;
            const paceLabel = (lang === 'en' ? 'mo ' : '월 ') + paceVal + '억';
            ctxd.fillText(paceLabel, bar.x, yMid + 8);
          } else {
            // 좁은 막대: 총량만
            ctxd.fillStyle = '#FF453A';
            ctxd.font = '600 11px ' + fontStack;
            ctxd.fillText(value + '억', bar.x, yMid);
          }
          ctxd.restore();
        });
      },
    };

    chartRef.current = new Chart(barRef.current, {
      type: 'bar',
      data: {
        labels: channels,
        datasets: [
          {
            label: t.actual,
            data: actualData,
            backgroundColor: accent + 'cc',
            borderRadius: 4,
            stack: 'channel',
          },
          {
            label: t.shortageAmount,
            data: shortageData,
            backgroundColor: 'rgba(255,69,58,0.15)',  // #FF453A 15% — 살짝 투명한 붉은색
            borderColor: 'rgba(255,69,58,0.7)',
            borderWidth: 1.5,
            borderDash: [4, 4],  // 점선 테두리
            borderRadius: 4,
            stack: 'channel',
          },
        ],
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        plugins: {
          legend: { labels: { color: fgMuted, font: { size: 11 }, boxWidth: 12 } },
          tooltip: {
            callbacks: {
              label: ctx => ` ${ctx.dataset.label}: ${ctx.raw}억`,
              // 부족분 호버 시 목표 대비 % 추가
              afterLabel: ctx => {
                if (ctx.datasetIndex !== 1) return null;
                const target = targetData[ctx.dataIndex];
                if (!target) return null;
                const pct = ctx.raw / target * 100;
                return ` (${(lang === 'en' ? 'vs target' : '목표 대비')} ${pct.toFixed(1)}%)`;
              },
            },
          },
        },
        scales: {
          x: { stacked: true, grid: { display: false }, ticks: { color: fgMuted } },
          y: { stacked: true, grid: { color: gridC }, ticks: { color: fgMuted, callback: v => v + '억' } },
        },
      },
      plugins: [shortageLabelPlugin],
    });
    return () => { if (chartRef.current) chartRef.current.destroy(); };
  }, [kpi, actuals, lang, showSecondary]);

  if (loading) return <KpiPlaceholder msg={t.loading}/>;
  if (err)     return <KpiPlaceholder msg={'Error: ' + err}/>;

  const totalTarget  = kpi?.Total?.revenue    || 0;
  const totalActual  = actuals?.total          || 0;
  const remaining    = Math.max(0, totalTarget - totalActual);
  const achRate      = totalTarget > 0 ? totalActual / totalTarget * 100 : null;
  const shortageRate = achRate != null ? Math.max(0, 100 - achRate) : null;

  return (
    <div>
      <header style={{ display:'flex', alignItems:'center', gap:12, marginBottom:16 }}>
        <h2 className="view-head" style={{ marginBottom:0 }}>{t.title}</h2>
        {/* 2024/2025 KPI targets not seeded yet — locking to 2026 to avoid infinite-loading state.
            TODO: when historical targets are added to kpi_targets table, restore [2026, 2025, 2024]. */}
        <select value={year} onChange={e => setYear(+e.target.value)} className="toolbar-select toolbar-select--md">
          {[2026].map(y => <option key={y} value={y}>{y}</option>)}
        </select>
      </header>

      {/* 4-card summary */}
      <div className="kpi-summary-grid" style={{ gridTemplateColumns:'repeat(4,1fr)' }}>
        {[
          { label: t.totalTarget, value: moneyKpi(totalTarget), note: null },
          { label: t.actualYtd,   value: moneyKpi(totalActual), note: null },
          { label: t.remaining,   value: moneyKpi(remaining),   note: null },
          // 달성률 ↔ 부족률 자동 토글 (showShortage가 3.5초마다 flip).
          // 부족률은 항상 주황(#FF9500)으로 표시 — 4월 시점 부족률 ~80%가
          // 자연스러운 상태라 빨강은 과함. 색 전환은 CSS transition으로 부드럽게.
          showShortage
            ? {
                label: t.shortage,
                value: shortageRate == null ? '—' : shortageRate.toFixed(1) + '%',
                color: '#FF9500',
                note: shortageRate != null ? `${t.remaining}: ${moneyKpi(remaining)}` : null,
              }
            : {
                label: t.achievement,
                value: achRate == null ? '—' : achRate.toFixed(1) + '%',
                color: achRate == null ? 'var(--fg)' : achRate >= 100 ? '#34C759' : achRate >= 70 ? '#FF9500' : '#FF453A',
                note: achRate != null ? `${t.target}: ${moneyKpi(totalTarget)}` : null,
              },
        ].map((k, i) => (
          <div key={i} className="kpi-mini">
            <div className="kpi-mini__label" style={{ transition: 'color 0.4s ease' }}>{k.label}</div>
            <div className="kpi-mini__value kpi-mini__value--md"
              style={{ color: k.color || undefined, transition: 'color 0.4s ease' }}>
              {k.value}
            </div>
            {k.note && <div className="kpi-mini__sub">{k.note}</div>}
          </div>
        ))}
      </div>

      {/* Channel bar chart — gated behind progressive render.
          Wrapped in KpiChartCard so the canvas (responsive +
          maintainAspectRatio:false) fills a fixed-height body. The single
          big chart of this view deserves the TALL height (320). */}
      <div style={{ marginBottom:16 }}>
        <KpiChartCard title={t.byChannel} height={KPI_CHART_HEIGHT}>
          {showSecondary
            ? <canvas ref={barRef} id="kpi-bar" style={{ position:'absolute', inset:0, width:'100%', height:'100%' }}/>
            : <div style={{ padding:'40px 0', textAlign:'center', color:'var(--fg-subtle)', fontSize:12 }}>{t.loading}</div>}
        </KpiChartCard>
      </div>

      {/* Cross-metrics row */}
      {kpi && (
        <div style={{ display:'grid', gridTemplateColumns:'repeat(3,1fr)', gap:12, marginBottom:16 }}>
          {[
            {
              label: 'US B2C 비중',
              target: kpi?.US?.b2c_share,
              actual: actuals?.usB2cShare,
              unit: '%',
            },
            {
              label: lang === 'en' ? 'US+ROW Bumper share' : 'US+ROW Bumper 비중',
              target: kpi?.['US+ROW']?.bumper_share,
              actual: actuals?.bumperShare,
              unit: '%',
            },
            {
              label: lang === 'en' ? 'Monthly avg needed' : '월 평균 필요 목표',
              target: achRate != null ? Math.round((totalTarget - totalActual) / Math.max(1, 12 - (new Date().getMonth() + 1)) / 1e8 * 10) / 10 : null,
              actual: null,
              unit: '억/월',
            },
          ].map((m, i) => (
            <div key={i} className="cross-metric-card">
              <div className="cross-metric-card__label">{m.label}</div>
              <div style={{ display:'flex', alignItems:'baseline', gap:6 }}>
                {m.actual != null && (
                  <span style={{ fontSize:20, fontWeight:700 }}>{m.actual.toFixed(1)}{m.unit}</span>
                )}
                {m.target != null && (
                  <span style={{ fontSize:12, color:'var(--fg-muted)' }}>
                    {m.actual != null ? '/ ' : ''}{t.target}: {m.target}{m.unit}
                  </span>
                )}
                {m.target == null && m.actual == null && (
                  <span style={{ fontSize:12, color:'var(--fg-muted)' }}>—</span>
                )}
              </div>
              {m.target != null && m.actual != null && (
                <AchBar pct={m.actual / m.target * 100}/>
              )}
            </div>
          ))}
        </div>
      )}

      {/* Monthly tracking table — gated behind progressive render */}
      <div className="surface-card">
        <h3 style={kpiSectionHead}>{t.monthlyTracking}</h3>
        {showSecondary
          ? <MonthlyTable actuals={actuals} kpi={kpi} year={year} lang={lang}/>
          : <div style={{ padding:'24px 0', textAlign:'center', color:'var(--fg-subtle)', fontSize:12 }}>{t.loading}</div>}
      </div>
    </div>
  );
}

// --- Aggregation helpers --------------------------------------------------
function buildKpiMap(targets) {
  const map = {};
  for (const t of (targets || [])) {
    if (!map[t.segment]) map[t.segment] = {};
    map[t.segment][t.metric] = t.target_value;
  }
  return map;
}

function buildActuals(rows, year) {
  const byChannel = { US: 0, ROW: 0, KR: 0 };
  const byMonth = {};  // 'YYYY-MM' → { US, ROW, KR, bumper }
  let total = 0;
  let usTotal = 0, usB2cTotal = 0;
  let bumperTotal = 0, usRowTotal = 0;

  for (const row of rows) {
    const date = row.order_date || '';
    if (!date || parseInt(date.slice(0, 4), 10) !== year) continue;

    const krw  = row.sales_amount_krw || 0;
    const ch   = row.channel_group || 'Other';
    const ym   = date.slice(0, 7);

    total += krw;
    if (ch in byChannel) byChannel[ch] += krw;

    if (!byMonth[ym]) byMonth[ym] = { US: 0, ROW: 0, KR: 0, Total: 0 };
    byMonth[ym][ch] = (byMonth[ym][ch] || 0) + krw;
    byMonth[ym].Total += krw;

    // Cross metrics
    if (ch === 'US') {
      usTotal += krw;
      if ((row.sales_channel || '').toUpperCase() === 'B2C') usB2cTotal += krw;
      bumperTotal  += row.category_group?.toUpperCase() === 'BUMPER' ? krw : 0;
      usRowTotal   += krw;
    }
    if (ch === 'ROW') {
      bumperTotal += row.category_group?.toUpperCase() === 'BUMPER' ? krw : 0;
      usRowTotal  += krw;
    }
  }

  const usB2cShare  = usTotal > 0 ? usB2cTotal  / usTotal  * 100 : null;
  const bumperShare = usRowTotal > 0 ? bumperTotal / usRowTotal * 100 : null;

  return { total, byChannel, byMonth, usB2cShare, bumperShare };
}

// --- Components -----------------------------------------------------------
function AchBar({ pct }) {
  const clamped = Math.min(pct, 100);
  const color   = pct >= 100 ? '#34C759' : pct >= 70 ? '#FF9500' : '#007AFF';
  return (
    <div style={{ background:'var(--surface-2)', borderRadius:99, height:4, overflow:'hidden', marginTop:4 }}>
      <div style={{ width: clamped + '%', height:'100%', background: color, borderRadius:99, transition:'width .4s ease' }}/>
    </div>
  );
}

function MonthlyTable({ actuals, kpi, year, lang }) {
  if (!actuals) return null;
  const months = Array.from({ length: 12 }, (_, i) => `${year}-${String(i + 1).padStart(2, '0')}`);
  const totalTarget = kpi?.Total?.revenue;
  const monthlyTarget = totalTarget ? totalTarget / 12 : null;

  // 잔여 월평균 필요액 — 채널별 부족분 / 잔여월수.
  // 잔여월수 = 12 - 현재월 (예: 4월이면 5~12월 = 8개월).
  // 부족분이 음수(=초과 달성)면 0으로 clamp — pace 표시 의미 없음.
  const monthsLeft = Math.max(1, 12 - (new Date().getMonth() + 1));
  const chShortage = (ch) => Math.max(0, (kpi?.[ch]?.revenue || 0) - (actuals.byChannel?.[ch] || 0));
  const pace = {
    US: chShortage('US') / monthsLeft,
    ROW: chShortage('ROW') / monthsLeft,
    KR: chShortage('KR') / monthsLeft,
  };
  pace.Total = pace.US + pace.ROW + pace.KR;

  return (
    <div style={{ overflowX: 'auto' }}>
      <table style={{ width:'100%', borderCollapse:'collapse', fontSize:12 }}>
        <thead>
          <tr>
            {[lang === 'en' ? 'Month' : '월', 'US', 'ROW', 'KR', 'Total',
              lang === 'en' ? 'Cum. Total' : '누적',
              lang === 'en' ? 'Ach %' : '달성률'].map((h, i) => (
              <th key={h} style={{ padding:'6px 10px', borderBottom:'1px solid var(--border)',
                textAlign: i === 0 ? 'left' : 'right',
                color:'var(--fg-muted)', fontWeight:600, textTransform:'uppercase', letterSpacing:.04,
              }}>{h}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {(() => {
            let cum = 0;
            let prevTot = null;  // previous month total for MoM delta
            return months.map(ym => {
              const m = actuals.byMonth[ym] || {};
              const tot = m.Total || 0;
              cum += tot;
              const pct = totalTarget ? cum / totalTarget * 100 : null;
              const monthLabel = ym.slice(5) + (lang === 'en' ? '' : '월');
              // MoM delta — only render once we have a positive previous total
              // AND the current month has data, otherwise show a dash.
              let momNode = null;
              if (tot > 0 && prevTot != null && prevTot > 0) {
                const pctMom = (tot - prevTot) / prevTot * 100;
                const arrow  = pctMom > 0 ? '▲' : pctMom < 0 ? '▼' : '—';
                const color  = pctMom > 0 ? '#34C759' : pctMom < 0 ? '#FF453A' : 'var(--fg-subtle)';
                const sign   = pctMom > 0 ? '+' : '';
                momNode = (
                  <span style={{ marginLeft:6, fontSize:10.5, color, fontWeight:500, fontVariantNumeric:'tabular-nums' }}>
                    {arrow} {sign}{pctMom.toFixed(1)}%
                  </span>
                );
              } else if (tot > 0 && prevTot != null) {
                // prevTot === 0 → infinite growth, just show neutral dash
                momNode = <span style={{ marginLeft:6, fontSize:10.5, color:'var(--fg-subtle)' }}>—</span>;
              }
              const row = (
                <tr key={ym} style={{ borderBottom:'1px solid var(--divider)' }}>
                  <td style={{ padding:'6px 10px', fontWeight:500 }}>{monthLabel}</td>
                  {['US', 'ROW', 'KR'].map(ch => (
                    <td key={ch} style={{ padding:'6px 10px', textAlign:'right', color:'var(--fg-2)' }}>
                      {m[ch] ? shortKrw(m[ch]) : '—'}
                    </td>
                  ))}
                  <td style={{ padding:'6px 10px', textAlign:'right', fontWeight:600, whiteSpace:'nowrap' }}>
                    {tot ? shortKrw(tot) : '—'}
                    {momNode}
                  </td>
                  <td style={{ padding:'6px 10px', textAlign:'right', color:'var(--fg-2)' }}>
                    {cum ? shortKrw(cum) : '—'}
                  </td>
                  <td style={{ padding:'6px 10px', textAlign:'right' }}>
                    {pct != null && tot > 0 ? (
                      <span style={{ color: pct >= 100 ? '#34C759' : pct >= 70 ? '#FF9500' : '#FF453A' }}>
                        {pct.toFixed(1)}%
                      </span>
                    ) : '—'}
                  </td>
                </tr>
              );
              // Track previous month total for next iteration. Only set when
              // tot > 0 so a leading run of empty months doesn't anchor MoM
              // to "0 → first non-zero = ∞ growth".
              if (tot > 0) prevTot = tot;
              return row;
            });
          })()}
          {/* Footer: 잔여 월평균 필요액 (채널 부족분 ÷ 잔여월수).
              주황 톤(#FF9500)으로 부족률 카드와 색 통일. */}
          <tr style={{
            borderTop: '2px solid var(--border)',
            background: 'rgba(255,149,0,0.06)',
          }}>
            <td style={{ padding:'10px', fontWeight:600, color:'var(--fg-muted)' }}>
              {lang === 'en' ? 'Required/mo' : '월평균 필요'}
              <span style={{ marginLeft:6, fontSize:10.5, color:'var(--fg-subtle)', fontWeight:400 }}>
                {lang === 'en' ? `(${monthsLeft} mo left)` : `(잔여 ${monthsLeft}개월)`}
              </span>
            </td>
            {['US', 'ROW', 'KR'].map(ch => (
              <td key={ch} style={{
                padding:'10px', textAlign:'right', fontWeight:600,
                color: pace[ch] > 0 ? '#FF9500' : 'var(--fg-subtle)',
              }}>
                {pace[ch] > 0 ? shortKrw(pace[ch]) : '—'}
              </td>
            ))}
            <td style={{
              padding:'10px', textAlign:'right', fontWeight:700,
              color: pace.Total > 0 ? '#FF9500' : 'var(--fg-subtle)',
            }}>
              {pace.Total > 0 ? shortKrw(pace.Total) : '—'}
            </td>
            <td style={{ padding:'10px', textAlign:'right', color:'var(--fg-subtle)' }}>—</td>
            <td style={{ padding:'10px', textAlign:'right', color:'var(--fg-subtle)' }}>—</td>
          </tr>
        </tbody>
      </table>
    </div>
  );
}

function KpiPlaceholder({ msg }) {
  return <div style={{ padding:40, textAlign:'center', color:'var(--fg-muted)', fontSize:14 }}>{msg}</div>;
}

function moneyKpi(n) {
  if (!n) return '—';
  return '₩' + (n / 1e8).toFixed(1).replace(/\.0$/, '') + '억';
}
function shortKrw(n) {
  if (!n) return '0';
  if (Math.abs(n) >= 1e8) return (n / 1e8).toFixed(1).replace(/\.0$/, '') + '억';
  return (n / 1e4).toFixed(0) + '만';
}

const kpiSectionHead = { fontSize:13, fontWeight:600, marginTop:0, marginBottom:12, color:'var(--fg-2)' };

// Unified chart-card sizing for the KPI Progress tab.
// This view has only one chart (channel target vs actual bar), so it gets
// the TALL height — a single big chart deserves more vertical room than
// the side-by-side rows in Overview/Product/Regional.
const KPI_CHART_HEIGHT = 320;

// Mirrors OvChartCard from view-overview.jsx — header + flex:1 body so a
// child <canvas> styled with absolute inset:0 fills the body precisely.
function KpiChartCard({ title, children, height = KPI_CHART_HEIGHT }) {
  return (
    <div className="chart-card" style={{ height }}>
      <h3 style={kpiSectionHead}>{title}</h3>
      <div className="chart-card__body">
        {children}
      </div>
    </div>
  );
}

const KT_KO = {
  title:'KPI 달성률', loading:'불러오는 중…',
  totalTarget:'전체 목표', actualYtd:'누적 실적', remaining:'잔여 목표',
  achievement:'달성률', shortage:'부족률', shortageAmount:'부족분',
  target:'목표', actual:'실적', byChannel:'채널별 달성률',
  monthlyTracking:'월별 트래킹',
};
const KT_EN = {
  title:'KPI Progress', loading:'Loading…',
  totalTarget:'Total Target', actualYtd:'Actual (YTD)', remaining:'Remaining',
  achievement:'Achievement', shortage:'Shortfall', shortageAmount:'Shortfall',
  target:'Target', actual:'Actual', byChannel:'By Channel',
  monthlyTracking:'Monthly Tracking',
};

window.KpiView = KpiView;
