// discover-filters.jsx — Advanced filter sheet for Discover screen
// ─────────────────────────────────────────────────────────────────────────
//  Surfaces every Supabase filterable field as a multi-select chip group:
//    provider, specialty, language, teaching mode, event type, audience,
//    enrolment status, plus quick deadline / points / fee ranges.
//
//  Design choices:
//    • Options are computed from the *currently loaded* COURSES set, not a
//      hard-coded enum. So if Supabase ships a new specialty next week,
//      it shows up without a code change. Each option carries its course
//      count — users can see which filters have results.
//    • Selections are multi-select OR within a facet, AND across facets.
//      Matches how nurses actually browse ("Cantonese OR English, but
//      definitely Cardiac AND must be Open").
//    • The sheet header has a live "X courses" count that updates as you
//      tick — so users know whether they're cutting too aggressively
//      before they hit Apply.
//    • Sticky footer with Reset (clears just *this* sheet) and the live
//      Apply button.
//
//  Public API:
//    DiscoverFilters.facets(courses)                  → derived facets
//    DiscoverFilters.applyFilters(courses, filters)   → filtered list
//    DiscoverFilters.countActive(filters)             → integer
//    DiscoverFilters.emptyFilters()                   → blank filter state
//    <DiscoverFilterSheet filters onChange onClose lang courses />
// ─────────────────────────────────────────────────────────────────────────

const { useState: dfS, useMemo: dfM, useEffect: dfE } = React;

// ── Facet config ──────────────────────────────────────────────────────────
// Each facet maps to an array field (multi-valued, like specialty_area_en)
// or a scalar (like language_en). The shape decides how applyFilters reads it.
const DF_FACETS = [
  { key: 'provider_code',     kind: 'scalar', label: { en: 'Provider',       zh: '主辦機構' } },
  { key: 'specialty_area_en', kind: 'array',  label: { en: 'Specialty',      zh: '專科' } },
  { key: 'event_type_en',     kind: 'scalar', label: { en: 'Event type',     zh: '類型' } },
  { key: 'language_en',       kind: 'scalar', label: { en: 'Language',       zh: '語言' } },
  { key: 'teaching_mode_en',  kind: 'scalar', label: { en: 'Teaching mode',  zh: '形式' } },
  { key: 'target_audience_en', kind: 'array', label: { en: 'For',            zh: '對象' } },
];

// Synonym mapping for translating raw EN values to ZH for display.
// Falls back to the EN value if we don't have a translation.
const DF_ZH_SYNONYMS = {
  // teaching modes
  'Online':                          '網上',
  'Face-to-face':                    '面授',
  'Zoom':                            'Zoom',
  'Online (Zoom)':                   '網上（Zoom）',
  'Self-study':                      '自學',
  'Mixed (Zoom + Face-to-face)':     'Zoom + 面授',
  // languages
  'Cantonese':                       '廣東話',
  'English':                         '英語',
  'Mandarin':                        '普通話',
  'Bilingual (Cantonese/English)':   '雙語（廣東話／英語）',
  'Bilingual (English/Mandarin)':    '雙語（英語／普通話）',
  'English PowerPoint, Cantonese verbal': '英文簡報 / 廣東話講授',
  // enrolment status
  'Open':                            '可報名',
  'Full':                            '已滿',
  'Closed':                          '已截止',
  'Enrollment ended':                '報名已結束',
  'Opening Soon':                    '即將開放',
  // specialty (most common)
  'Critical Care':                   '危重病護理',
  'Cardiac':                         '心臟科',
  'Emergency':                       '急症',
  'Oncology':                        '腫瘤科',
  'Paediatrics':                     '兒科',
  'Mental Health':                   '精神健康',
  'Orthopaedics':                    '骨科',
  'Renal':                           '腎科',
  'Respiratory':                     '呼吸科',
  'Obstetrics':                      '婦產科',
  'Palliative':                      '紓緩護理',
  'Infection Control':               '感染控制',
  'Wound Care':                      '傷口護理',
  'Endoscopy':                       '內窺鏡',
  'Diabetes':                        '糖尿病',
  'Neurology':                       '神經科',
  'Urology':                         '泌尿科',
  'Gerontology':                     '老人科',
  'Perioperative':                   '手術室護理',
  'Community':                       '社區',
  'Management':                      '管理',
  'Research':                        '研究',
  'Education':                       '教育',
  'General':                         '一般',
  // audience
  'RN':                              '註冊護士',
  'EN':                              '登記護士',
  'Midwife':                         '助產士',
  'Student Nurse':                   '學生護士',
  'APN':                             '高級執業護士',
  'Advanced Practice Nurses':        '高級執業護士',
  'Allied Health':                   '醫療輔助人員',
  'Doctor':                          '醫生',
  'Healthcare Professional':         '醫護人員',
  'Healthcare Professionals':        '醫護人員',
  'Nurses':                          '護士',
  'Specialist Nurse':                '專科護士',
  'Nursing managers and nurses in leadership roles': '護理管理及領導職位',
  'Nursing Manager':                 '護理管理',
  'General public and caregivers':   '公眾及照顧者',
  'Nurses & Allied Health':          '護士及醫療輔助人員',
};

function dfZh(en) {
  return DF_ZH_SYNONYMS[en] || en;
}

// Build a fresh empty filter state. Each facet gets a Set; ranges get null.
function dfEmpty() {
  const out = { search: '', cost: null, mode: null, deadlineDays: null, points: null };
  DF_FACETS.forEach(f => { out[f.key] = []; });
  return out;
}

// Compute facet → option list with counts, from the live courses set.
// Each option = { value: 'AHKNS', count: 23, label: { en, zh } }
function dfFacets(courses) {
  const list = Array.isArray(courses) ? courses : [];
  const buckets = {};
  DF_FACETS.forEach(f => { buckets[f.key] = new Map(); });

  list.forEach(c => {
    const r = c.raw || {};
    DF_FACETS.forEach(f => {
      const raw = r[f.key];
      if (f.kind === 'array') {
        if (Array.isArray(raw)) {
          raw.forEach(v => {
            if (!v) return;
            const k = String(v);
            buckets[f.key].set(k, (buckets[f.key].get(k) || 0) + 1);
          });
        }
      } else {
        if (raw == null || raw === '') return;
        const k = String(raw);
        buckets[f.key].set(k, (buckets[f.key].get(k) || 0) + 1);
      }
    });
  });

  const out = {};
  DF_FACETS.forEach(f => {
    out[f.key] = [...buckets[f.key].entries()]
      .map(([value, count]) => ({
        value, count,
        label: { en: value, zh: dfZh(value) },
      }))
      .sort((a, b) => b.count - a.count || a.value.localeCompare(b.value));
  });
  return out;
}

// Apply filters to a course list. AND across facets, OR within a facet.
function dfApply(courses, f) {
  if (!f) return courses;
  return (courses || []).filter(c => {
    const r = c.raw || {};
    for (const facet of DF_FACETS) {
      const sel = f[facet.key];
      if (!sel || sel.length === 0) continue;
      const raw = r[facet.key];
      if (facet.kind === 'array') {
        if (!Array.isArray(raw) || !raw.some(v => sel.includes(String(v)))) return false;
      } else {
        if (raw == null || !sel.includes(String(raw))) return false;
      }
    }
    if (f.points) {
      const p = Number(c.points);
      if (!Number.isFinite(p) || p < f.points[0] || p > f.points[1]) return false;
    }
    if (f.cost === 'free' && Number(c.cost) > 0) return false;
    if (f.cost === 'paid' && (!Number(c.cost) || Number(c.cost) === 0)) return false;
    if (f.deadlineDays != null) {
      const today = new Date().toISOString().slice(0, 10);
      const d = c.registrationDeadline || r.registration_deadline;
      if (!d) return false;
      const diff = Math.round((new Date(d + 'T00:00:00') - new Date(today + 'T00:00:00')) / 86400000);
      if (diff < 0 || diff > f.deadlineDays) return false;
    }
    return true;
  });
}

function dfCountActive(f) {
  if (!f) return 0;
  let n = 0;
  DF_FACETS.forEach(facet => { if ((f[facet.key] || []).length) n++; });
  if (f.cost) n++;
  if (f.points) n++;
  if (f.deadlineDays != null) n++;
  return n;
}

// ─────────────────────────────────────────────────────────────────────────
// <DiscoverFilterSheet> — the sheet itself
// ─────────────────────────────────────────────────────────────────────────
function DiscoverFilterSheet({ open, onClose, filters, onApply, lang, courses }) {
  // Local draft state — we only commit on Apply so users can experiment.
  const [draft, setDraft] = dfS(() => ({ ...dfEmpty(), ...filters }));
  dfE(() => { if (open) setDraft({ ...dfEmpty(), ...filters }); }, [open]);

  const facets = dfM(() => dfFacets(courses), [courses]);
  const matchCount = dfM(() => dfApply(courses, draft).length, [courses, draft]);
  const activeN = dfCountActive(draft);

  if (!open) return null;

  const toggle = (key, value) => {
    setDraft(d => {
      const cur = d[key] || [];
      const has = cur.includes(value);
      return { ...d, [key]: has ? cur.filter(v => v !== value) : [...cur, value] };
    });
  };

  const renderFacet = (facet) => {
    const opts = facets[facet.key] || [];
    if (opts.length === 0) return null;
    const selected = draft[facet.key] || [];

    // Long lists (provider, event type) get a scrollable region.
    const isLong = opts.length > 12;

    return (
      <div key={facet.key} className="df-section">
        <div className="df-section-head">
          <div className="df-section-title">{L(facet.label, lang)}</div>
          {selected.length > 0 && (
            <button className="df-section-clear" onClick={() => setDraft(d => ({ ...d, [facet.key]: [] }))}>
              {lang === 'zh' ? '清除' : 'Clear'}
            </button>
          )}
        </div>
        <div className={'df-chips' + (isLong ? ' df-chips-scroll' : '')}>
          {opts.map(o => {
            const on = selected.includes(o.value);
            return (
              <button
                key={o.value}
                type="button"
                className={'df-chip' + (on ? ' on' : '')}
                onClick={() => toggle(facet.key, o.value)}
                aria-pressed={on}>
                <span className="df-chip-label">{L(o.label, lang)}</span>
                <span className="df-chip-count">{o.count}</span>
              </button>
            );
          })}
        </div>
      </div>
    );
  };

  return (
    <div className="df-backdrop" onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="df-sheet" role="dialog" aria-modal="true" aria-label={L(STR.filters, lang)}>
        <div className="df-handle" aria-hidden="true" />
        <div className="df-head">
          <div className="df-head-title">{L(STR.filters, lang)}</div>
          <button className="icon-btn" onClick={onClose} aria-label={lang === 'zh' ? '關閉' : 'Close'}>
            <Icon name="close" size={16} />
          </button>
        </div>

        <div className="df-body">
          {/* Quick row: cost + deadline */}
          <div className="df-section">
            <div className="df-section-head">
              <div className="df-section-title">{lang === 'zh' ? '快速篩選' : 'Quick filters'}</div>
            </div>
            <div className="df-chips">
              <button className={'df-chip' + (draft.cost === 'free' ? ' on' : '')}
                onClick={() => setDraft(d => ({ ...d, cost: d.cost === 'free' ? null : 'free' }))}>
                <span className="df-chip-label">{L(STR.free, lang)}</span>
              </button>
              <button className={'df-chip' + (draft.cost === 'paid' ? ' on' : '')}
                onClick={() => setDraft(d => ({ ...d, cost: d.cost === 'paid' ? null : 'paid' }))}>
                <span className="df-chip-label">{lang === 'zh' ? '付費' : 'Paid'}</span>
              </button>
              {[7, 14, 30].map(n => (
                <button key={n} className={'df-chip' + (draft.deadlineDays === n ? ' on' : '')}
                  onClick={() => setDraft(d => ({ ...d, deadlineDays: d.deadlineDays === n ? null : n }))}>
                  <span className="df-chip-label">
                    {lang === 'zh' ? `${n} 日內截止` : `Deadline ≤ ${n}d`}
                  </span>
                </button>
              ))}
            </div>
          </div>

          {DF_FACETS.map(renderFacet)}

          {/* CNE points range */}
          <div className="df-section">
            <div className="df-section-head">
              <div className="df-section-title">{L(STR.filterPoints, lang)}</div>
              {draft.points && (
                <button className="df-section-clear" onClick={() => setDraft(d => ({ ...d, points: null }))}>
                  {lang === 'zh' ? '清除' : 'Clear'}
                </button>
              )}
            </div>
            <div className="df-chips">
              {[[1,3],[3,6],[6,12],[12,30]].map(([a,b]) => {
                const on = draft.points && draft.points[0] === a && draft.points[1] === b;
                return (
                  <button key={`${a}-${b}`} className={'df-chip' + (on ? ' on' : '')}
                    onClick={() => setDraft(d => ({ ...d, points: on ? null : [a, b] }))}>
                    <span className="df-chip-label">{a}–{b} {L(STR.pts, lang)}</span>
                  </button>
                );
              })}
            </div>
          </div>
        </div>

        <div className="df-foot">
          <button className="btn btn-ghost" onClick={() => setDraft(dfEmpty())}
            disabled={activeN === 0}>
            {L(STR.filtersReset, lang)}
          </button>
          <button className="btn btn-primary df-apply" onClick={() => { onApply(draft); onClose(); }}>
            <span>{L(STR.filtersApply, lang)}</span>
            <span className="df-apply-count">{matchCount}</span>
          </button>
        </div>
      </div>
    </div>
  );
}

window.DiscoverFilters = {
  facets: dfFacets,
  applyFilters: dfApply,
  countActive: dfCountActive,
  emptyFilters: dfEmpty,
  FACETS: DF_FACETS,
  zh: dfZh,
};
window.DiscoverFilterSheet = DiscoverFilterSheet;
