// Helper321 Admin — Growth: acquisition report and lead list (T-008, API_GUIDE §6.21).
// Both pages are read-only. Pure helpers live in admin-acquisition-model.js.
const AcqModel = window.AdminAcquisitionModel;

const saveAcquisitionCsv = (text, prefix) => {
  const url = URL.createObjectURL(new Blob([text], { type: 'text/csv;charset=utf-8' }));
  const link = document.createElement('a');
  try {
    link.href = url;
    link.download = `${prefix}-${new Date().toISOString().replace(/[:.]/g, '-')}.csv`;
    document.body.appendChild(link);
    link.click();
  } finally {
    link.remove();
    setTimeout(() => URL.revokeObjectURL(url), 1000);
  }
};

// Also used by the Dashboard "匯出週報" button.
const downloadAcquisitionReport = async (api, weeks = 8) => {
  const report = await api.getAcquisitionReport(weeks);
  saveAcquisitionCsv(AcqModel.buildAcquisitionCsv(report), `acquisition-${weeks}w`);
};

// The lead API pages at ≤ 200 rows. Load the whole filter so the eligibility
// share and the CSV cover every matching lead, not just one page.
const LEAD_FETCH_SIZE = 200;
const LEAD_FETCH_MAX_PAGES = 25;
const loadAllLeads = async (api, filter) => {
  const leads = [];
  let page = 1, totalPages = 1, total = 0;
  do {
    const response = await api.getLeads({ ...filter, page, page_size: LEAD_FETCH_SIZE });
    leads.push(...(response?.data || []));
    totalPages = response?.meta?.total_pages || 1;
    total = response?.meta?.total ?? leads.length;
    page += 1;
  } while (page <= totalPages && page <= LEAD_FETCH_MAX_PAGES);
  return { leads, total, truncated: leads.length < total };
};

// Keyed results hide obsolete data immediately and discard late responses.
const useAcquisitionResource = (key, load) => {
  const [state, setState] = React.useState({ key: null, data: null, error: null, loading: true });
  const [revision, setRevision] = React.useState(0);
  React.useEffect(() => {
    let cancelled = false;
    setState({ key, data: null, error: null, loading: true });
    Promise.resolve().then(load).then(
      data => { if (!cancelled) setState({ key, data, error: null, loading: false }); },
      error => { if (!cancelled) setState({ key, data: null, error, loading: false }); },
    );
    return () => { cancelled = true; };
  }, [key, revision]);
  return {
    ...(state.key === key ? state : { data: null, error: null, loading: true }),
    retry: () => { setState({ key, data: null, error: null, loading: true }); setRevision(x => x + 1); },
  };
};

const AcquisitionError = ({ error, retry }) => (
  <div role="alert" style={{padding:16}}>
    <p>{error.status === 401 ? '登入已失效，請重新登入。' : error.status === 403 ? '您沒有權限查看此資料。' : '無法載入資料，請稍後重試。'}</p>
    <button className="a-btn a-btn-default" onClick={retry}>重試</button>
  </div>
);

const AcquisitionNote = ({ title, children, tone = 'warn' }) => (
  <div className="mb-16" role={tone === 'danger' ? 'alert' : undefined} style={tone === 'danger'
    ? {padding:16,background:'var(--a-danger-bg)',border:'1px solid var(--a-danger-line)',borderRadius:10}
    : {padding:16,background:'#FFF8EC',border:'1px solid #F7D27A',borderRadius:10}}>
    <strong>{title}</strong><div className="fs-12">{children}</div>
  </div>
);

const AcqBadge = ({ conf, fallback, title }) => conf
  ? <span className={`a-badge a-badge-${conf.kind}`} title={title}>{conf.label}</span>
  : <span className="text-muted">{fallback || '—'}</span>;

// ---------- 來源週報 ----------
const AcquisitionPage = () => {
  const { t } = useI18n();
  const toast = useToast();
  const api = window.Helper321AdminApi;
  const [weeks, setWeeks] = React.useState(8);
  const [expanded, setExpanded] = React.useState(() => new Set());
  const report = useAcquisitionResource(String(weeks), () => api.getAcquisitionReport(weeks));
  const rows = [...(report.data?.weeks || [])].sort((a, b) => String(b.week_start).localeCompare(String(a.week_start)));
  const totals = AcqModel.sumWeeks(rows);
  const now = new Date();
  const toggle = (key) => setExpanded(current => {
    const next = new Set(current);
    if (next.has(key)) next.delete(key); else next.add(key);
    return next;
  });
  const exportCsv = () => {
    if (!report.data) return;
    try {
      saveAcquisitionCsv(AcqModel.buildAcquisitionCsv(report.data), `acquisition-${weeks}w`);
      toast(`已下載最近 ${weeks} 週的來源週報 CSV`, 'success');
    } catch { toast('無法匯出 CSV，請稍後再試。', 'danger'); }
  };
  const metricCells = (row) => AcqModel.METRICS.map(m => <td key={m.key} className="a-table-num">{row?.[m.key] ?? 0}</td>);
  return <div className="a-page">
    <div className="a-page-header">
      <div><h1 className="a-page-title">{t('admin.menu.acquisition')}</h1><p className="a-page-sub">每週真實的註冊、送審和需求數，依來源拆開。週一到週日，台北時間。</p></div>
      <div className="a-page-header-actions">
        <select className="a-select" aria-label="週數" style={{width:130}} value={weeks} onChange={event => { setExpanded(new Set()); setWeeks(Number(event.target.value)); }}>
          {[4, 8, 12, 26].map(n => <option key={n} value={n}>最近 {n} 週</option>)}
        </select>
        <button className="a-btn a-btn-default" onClick={report.retry} disabled={report.loading}><AIcon name="refresh" size={14}/> 重新整理</button>
        <button className="a-btn a-btn-default" onClick={exportCsv} disabled={!report.data}><AIcon name="download" size={14}/> 匯出 CSV</button>
      </div>
    </div>
    <AcquisitionNote title="只算真實資料">
      不含 Demo 帳號、名字或訊息有「[TEST]」的名單，也不含 helper321.demo 網域的帳號。封存的帳號照算。2026-10-23 以前註冊的帳號沒有來源紀錄，會算在 (direct)。點一週可以看各來源的明細。
    </AcquisitionNote>
    <div className="a-card" style={{padding:0,overflow:'hidden'}}>
      {report.loading ? <p role="status" style={{padding:16}}>載入週報中…</p> : report.error ? <AcquisitionError error={report.error} retry={report.retry}/> : <>
        <table className="a-table">
          <thead><tr>
            <th>週（來源 / 媒介 · 活動）</th>
            {AcqModel.METRICS.map(m => <th key={m.key} className="a-table-num" style={{width:96}}>{m.label}</th>)}
          </tr></thead>
          <tbody>
            {rows.length === 0 && <tr><td colSpan={AcqModel.METRICS.length + 1}>沒有資料。</td></tr>}
            {rows.map(week => {
              const open = expanded.has(week.week_start);
              const sources = AcqModel.sortedSources(week);
              return <React.Fragment key={week.week_start}>
                <tr className="clickable" onClick={() => toggle(week.week_start)}>
                  <td>
                    <button type="button" className="a-icon-btn" aria-expanded={open} aria-label={`${open ? '收合' : '展開'} ${week.week_start} 的來源明細`} onClick={event => { event.stopPropagation(); toggle(week.week_start); }} style={{marginRight:6}}>
                      <AIcon name={open ? 'chevDown' : 'chevRight'} size={14}/>
                    </button>
                    <span className="fw-600 tnum" style={{whiteSpace:'nowrap'}}>{week.week_start} – {week.week_end}</span>
                    {AcqModel.isCurrentWeek(week, now) && <span className="a-badge a-badge-info" style={{marginLeft:8}}>進行中</span>}
                  </td>
                  {metricCells(week.totals)}
                </tr>
                {open && sources.length === 0 && <tr><td colSpan={AcqModel.METRICS.length + 1} className="fs-12 text-muted" style={{paddingLeft:48}}>這週沒有資料。</td></tr>}
                {open && sources.map(src => <tr key={AcqModel.sourceLabel(src)} style={{background:'var(--a-paper-2)'}}>
                  <td className="fs-12" style={{paddingLeft:48,overflowWrap:'anywhere'}}>{AcqModel.sourceLabel(src)}</td>
                  {metricCells(src)}
                </tr>)}
              </React.Fragment>;
            })}
          </tbody>
          {rows.length > 0 && <tfoot><tr>
            <td className="fw-600" style={{padding:'10px 16px'}}>合計（最近 {rows.length} 週）</td>
            {AcqModel.METRICS.map(m => <td key={m.key} className="a-table-num fw-600" style={{padding:'10px 16px'}}>{totals[m.key]}</td>)}
          </tr></tfoot>}
        </table>
      </>}
    </div>
    {report.data?.generated_at && <p className="fs-12 text-muted" style={{marginTop:8}}>資料時間：{AcqModel.formatTaipei(report.data.generated_at)}（台北）</p>}
  </div>;
};

// ---------- 需求名單 ----------
const LEAD_PAGE_SIZE = 50;

const leadRange = (preset, custom, now) => {
  if (preset === 'this_week') return AcqModel.taipeiWeekRange(now, 0);
  if (preset === 'last_week') return AcqModel.taipeiWeekRange(now, -1);
  if (preset === 'last_30') return AcqModel.lastDaysRange(now, 30);
  if (preset === 'custom') return { from: custom.from, to: custom.to };
  return { from: '', to: '' };
};

const leadContact = (lead) => [lead.phone, lead.email, lead.line_id && `LINE ${lead.line_id}`].filter(Boolean);

const LeadDrawer = ({ lead, onClose }) => {
  if (!lead) return null;
  const d = AcqModel.detailsOf(lead);
  const src = AcqModel.sourceOf(lead);
  const rows = [
    ['建立時間', `${AcqModel.formatTaipei(lead.created_at)}（台北）`],
    ['類型', lead.kind === 'employer_demand' ? '雇主需求' : '聯絡表單'],
    ['主題', AcqModel.TOPICS[lead.topic] || lead.topic],
    ['看護／幫傭', AcqModel.CARE_TYPES[d.care_type] || d.care_type],
    ['縣市', d.city],
    ['資格確認', AcqModel.ELIGIBILITY[d.eligibility_status]?.label || d.eligibility_status],
    ['家庭狀況', Array.isArray(d.household) ? d.household.map(x => AcqModel.HOUSEHOLD_FLAGS[x] || x).join('、') : null],
    ['預計開始', AcqModel.START_TIMELINES[d.start_timeline] || d.start_timeline],
    ['現有移工', AcqModel.CURRENT_WORKERS[d.current_worker] || d.current_worker],
    ['電話', lead.phone], ['Email', lead.email], ['LINE', lead.line_id],
    ['偏好聯絡方式', AcqModel.PREFERRED_CONTACTS[d.preferred_contact] || d.preferred_contact],
    ['方便聯絡時間', d.contact_time],
    ['訊息', lead.message],
    ['跟進狀態', AcqModel.LEAD_STATUSES[lead.status]?.label || lead.status],
    ['備註', lead.note],
    ['通知信', AcqModel.EMAIL_STATUSES[lead.email_status]?.label || lead.email_status],
    ['通知錯誤', lead.email_error],
    ['來源', AcqModel.sourceLabel(src)],
    ['utm_term', lead.utm_term], ['utm_content', lead.utm_content],
    ['登陸頁', lead.landing_path], ['送出頁面', lead.source_page], ['外部來源網址', lead.referrer],
    ['同意條款時間', lead.consent_at ? `${AcqModel.formatTaipei(lead.consent_at)}（台北）` : null],
    ['語系', lead.locale], ['測試資料', lead.is_demo ? '是' : null], ['名單 ID', lead.id],
  ].filter(([, value]) => value !== null && value !== undefined && value !== '');
  return <ADrawer open onClose={onClose} title={lead.name || '名單'}>
    <dl className="a-dl">
      {rows.map(([label, value]) => <React.Fragment key={label}><dt>{label}</dt><dd style={{overflowWrap:'anywhere',whiteSpace:'pre-wrap'}}>{value}</dd></React.Fragment>)}
    </dl>
  </ADrawer>;
};

const LeadsPage = () => {
  const { user } = useAuth();
  const { t } = useI18n();
  const toast = useToast();
  const api = window.Helper321AdminApi;
  const [kind, setKind] = React.useState('employer_demand');
  const [preset, setPreset] = React.useState('all');
  const [custom, setCustom] = React.useState({ from: '', to: '' });
  const [includeDemo, setIncludeDemo] = React.useState(false);
  const [offset, setOffset] = React.useState(0);
  const [openId, setOpenId] = React.useState(null);
  const range = leadRange(preset, custom, new Date());
  const filter = { kind, from: range.from, to: range.to, include_demo: includeDemo ? 'true' : '' };
  const list = useAcquisitionResource(JSON.stringify(filter), () => loadAllLeads(api, filter));
  const leads = list.data?.leads || [];
  const pageOffset = AcqModel.leadPageOffset(leads.length, offset, LEAD_PAGE_SIZE);
  const pageRows = leads.slice(pageOffset, pageOffset + LEAD_PAGE_SIZE);
  const attention = leads.filter(AcqModel.emailNeedsAttention);
  const share = AcqModel.eligibilityShare(leads);
  const bySource = AcqModel.eligibilityBySource(leads);
  const isDemand = kind === 'employer_demand';
  const reset = (apply) => { setOffset(0); setOpenId(null); apply(); };
  const exportCsv = () => {
    if (!isSuperAdmin(user) || !leads.length) return;
    try {
      saveAcquisitionCsv(AcqModel.buildLeadsCsv(leads), `leads-${kind}`);
      toast(`已開始下載 ${leads.length} 筆名單的 CSV`, 'success');
    } catch { toast('無法匯出 CSV，請稍後再試。', 'danger'); }
  };
  const pct = (value) => (value === null ? '—' : `${value}%`);
  return <div className="a-page">
    <div className="a-page-header">
      <div><h1 className="a-page-title">{t('admin.menu.leads')}</h1><p className="a-page-sub">登陸頁需求表單和聯絡表單送進來的名單。這一頁只能看，不能修改。</p></div>
      <div className="a-page-header-actions">
        <button className="a-btn a-btn-default" onClick={list.retry} disabled={list.loading}><AIcon name="refresh" size={14}/> 重新整理</button>
        {isSuperAdmin(user) && <button className="a-btn a-btn-default" onClick={exportCsv} disabled={list.loading || Boolean(list.error) || !leads.length}><AIcon name="download" size={14}/> 匯出 CSV</button>}
      </div>
    </div>
    {attention.length > 0 && <AcquisitionNote tone="danger" title={`有 ${attention.length} 筆名單的通知寄送狀態需要確認`}>
      通知尚未確認寄出或寄送失敗；逾時也可能已由寄信服務接收。請先查核寄送紀錄，並從這一頁跟進名單（下方標紅的列）。「已寄出」只表示寄信服務收下了，不保證一定進到收件匣。
    </AcquisitionNote>}
    <AcquisitionNote title="跟進狀態只能在這裡看">
      後台還不能修改跟進狀態。請照名單跟進節奏，把狀態記在管道成本表的「名單追蹤」分頁。
    </AcquisitionNote>
    <div className="a-card" style={{padding:0,overflow:'hidden'}}>
      <div className="a-tabs" role="tablist" style={{padding:'0 16px',borderBottom:'1px solid var(--a-line)'}}>
        {[['employer_demand', '雇主需求'], ['contact', '聯絡表單']].map(([key, label]) =>
          <button key={key} type="button" role="tab" aria-selected={kind === key} className={`a-tab ${kind === key ? 'active' : ''}`} onClick={() => reset(() => setKind(key))}>{label}</button>)}
      </div>
      <div className="a-table-toolbar">
        <select className="a-select" aria-label="期間" style={{width:140}} value={preset} onChange={event => reset(() => setPreset(event.target.value))}>
          <option value="all">全部期間</option>
          <option value="this_week">本週</option>
          <option value="last_week">上週</option>
          <option value="last_30">最近 30 天</option>
          <option value="custom">自訂</option>
        </select>
        {preset === 'custom' && <>
          <input className="a-input" type="date" aria-label="開始日期" style={{width:150}} value={custom.from} max={custom.to || undefined} onChange={event => { const from = event.target.value; reset(() => setCustom(c => ({ ...c, from }))); }}/>
          <span className="text-muted">到</span>
          <input className="a-input" type="date" aria-label="結束日期" style={{width:150}} value={custom.to} min={custom.from || undefined} onChange={event => { const to = event.target.value; reset(() => setCustom(c => ({ ...c, to }))); }}/>
        </>}
        {preset !== 'all' && preset !== 'custom' && <span className="fs-12 text-muted tnum">{range.from} – {range.to}</span>}
        <label className="fs-12"><input type="checkbox" checked={includeDemo} onChange={event => { const checked = event.target.checked; reset(() => setIncludeDemo(checked)); }}/> 包含測試資料</label>
        <span className="text-muted fs-13" style={{marginLeft:'auto'}}>{list.loading ? '載入中…' : list.error ? '' : `共 ${list.data.total} 筆`}</span>
      </div>
      {list.loading ? <p role="status" style={{padding:16}}>載入名單中…</p> : list.error ? <AcquisitionError error={list.error} retry={list.retry}/> : <>
        {list.data.truncated && <p className="fs-12" style={{padding:'8px 16px',background:'var(--a-warn-bg)'}}>名單太多，只載入前 {leads.length} 筆。請縮小期間。</p>}
        {isDemand && leads.length > 0 && <div style={{padding:16,borderBottom:'1px solid var(--a-line)'}}>
          <div className="grid-4 mb-12">
            {[
              ['雇主需求', share.total, null],
              ['資格已確認', share.confirmed, `占 ${pct(share.confirmedPct)}`],
              ['資格不確定', share.unsure, null],
              ['資格不符或不知道', share.not_eligible_or_unknown, share.missing ? `另有 ${share.missing} 筆沒填` : null],
            ].map(([label, value, foot]) => <div className="a-stat" key={label}>
              <div className="a-stat-label">{label}</div><div className="a-stat-value tnum">{value}</div>{foot && <div className="a-stat-foot">{foot}</div>}
            </div>)}
          </div>
          <table className="a-table a-table-compact" aria-label="各來源的資格確認">
            <thead><tr><th>來源 / 媒介 · 活動</th><th className="a-table-num" style={{width:90}}>需求數</th><th className="a-table-num" style={{width:90}}>已確認</th><th className="a-table-num" style={{width:110}}>已確認占比</th></tr></thead>
            <tbody>{bySource.map(row => <tr key={AcqModel.sourceLabel(row)}>
              <td className="fs-12" style={{overflowWrap:'anywhere'}}>{AcqModel.sourceLabel(row)}</td>
              <td className="a-table-num">{row.total}</td><td className="a-table-num">{row.confirmed}</td><td className="a-table-num">{pct(row.confirmedPct)}</td>
            </tr>)}</tbody>
          </table>
        </div>}
        <table className="a-table">
          <thead><tr>
            <th style={{width:130}}>時間（台北）</th>
            <th>姓名</th>
            {isDemand ? <><th style={{width:150}}>需求</th><th style={{width:130}}>資格確認</th></> : <><th style={{width:100}}>主題</th><th>訊息</th></>}
            <th>聯絡方式</th>
            <th>來源</th>
            <th style={{width:90}}>跟進狀態</th>
            <th style={{width:96}}>通知信</th>
          </tr></thead>
          <tbody>
            {pageRows.length === 0 && <tr><td colSpan={8}><AEmpty icon="list" title="沒有符合條件的名單"/></td></tr>}
            {pageRows.map(lead => {
              const d = AcqModel.detailsOf(lead);
              const flagged = AcqModel.emailNeedsAttention(lead);
              return <tr key={lead.id} className="clickable" onClick={() => setOpenId(lead.id)} style={flagged ? {background:'var(--a-danger-bg)'} : undefined}>
                <td className="fs-12 tnum" style={{whiteSpace:'nowrap'}}>{AcqModel.formatTaipei(lead.created_at)}</td>
                <td style={{whiteSpace:'nowrap'}}><button type="button" className="fw-600" style={{background:'none',border:0,padding:0,color:'inherit',cursor:'pointer',textAlign:'left'}} onClick={event => { event.stopPropagation(); setOpenId(lead.id); }}>{lead.name || '—'}</button>{lead.is_demo && <span className="a-chip" style={{marginLeft:6}}>測試</span>}</td>
                {isDemand ? <>
                  <td className="fs-12">{AcqModel.CARE_TYPES[d.care_type] || d.care_type || '—'}<div className="text-muted">{d.city || '—'}</div></td>
                  <td><AcqBadge conf={AcqModel.ELIGIBILITY[d.eligibility_status]} fallback={d.eligibility_status}/></td>
                </> : <>
                  <td className="fs-12">{AcqModel.TOPICS[lead.topic] || lead.topic || '—'}</td>
                  <td className="fs-12" style={{maxWidth:280,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}} title={lead.message || ''}>{lead.message || '—'}</td>
                </>}
                <td className="fs-12" style={{overflowWrap:'anywhere'}}>{leadContact(lead).map(x => <div key={x}>{x}</div>)}{leadContact(lead).length === 0 && '—'}</td>
                <td className="fs-12" style={{overflowWrap:'anywhere'}}>{AcqModel.sourceLabel(AcqModel.sourceOf(lead))}</td>
                <td><AcqBadge conf={AcqModel.LEAD_STATUSES[lead.status]} fallback={lead.status}/></td>
                <td><AcqBadge conf={AcqModel.EMAIL_STATUSES[lead.email_status]} fallback={lead.email_status} title={lead.email_error || undefined}/></td>
              </tr>;
            })}
          </tbody>
        </table>
        {leads.length > LEAD_PAGE_SIZE && <div className="flex items-center gap-8" style={{padding:12,flexWrap:'wrap'}}>
          <button className="a-btn a-btn-default" disabled={pageOffset === 0} onClick={() => setOffset(Math.max(0, pageOffset - LEAD_PAGE_SIZE))}>上一頁</button>
          <span className="fs-12">第 {Math.floor(pageOffset / LEAD_PAGE_SIZE) + 1} 頁 · 共 {leads.length} 筆</span>
          <button className="a-btn a-btn-default" disabled={pageOffset + LEAD_PAGE_SIZE >= leads.length} onClick={() => setOffset(pageOffset + LEAD_PAGE_SIZE)}>下一頁</button>
        </div>}
      </>}
    </div>
    <LeadDrawer lead={leads.find(lead => lead.id === openId)} onClose={() => setOpenId(null)}/>
  </div>;
};

Object.assign(window, { AcquisitionPage, LeadsPage, downloadAcquisitionReport });
