// ============================================================================
// CWR CERTIFICATION RUNBOOK
// ----------------------------------------------------------------------------
// Per-society status tracker with the steps required to get production-ready
// with each society. This is the operational gate between "generates files"
// and "files are accepted in production."
//
// Statuses:
//   uncertified  — never tested with this society
//   credentials  — submitter ID requested, awaiting assignment
//   testing      — exchanging test transmissions
//   conformance  — society conformance review pending
//   certified    — production-cleared
//   suspended    — society temporarily blocking submissions
//
// EXPORT: window.CwrCertTab (tab inside Compliance dashboard)
// ============================================================================

(function () {
  const { useState, useMemo, useEffect } = React;

  const STORAGE_KEY = 'astro:cwr:certifications';

  // Default certification state — what a brand-new tenant looks like
  const DEFAULT_STATE = {
    ASCAP:  { status: 'certified',   submitterId: 'IPI 199900001',  testFiles: 12, testFilesPassed: 12, certifiedDate: '2024-08-14', notes: 'Production active. Last filing 2024-12-02.' },
    BMI:    { status: 'certified',   submitterId: 'BMI-PUB-7745',   testFiles: 10, testFilesPassed: 10, certifiedDate: '2024-09-03', notes: 'Production active.' },
    SESAC:  { status: 'testing',     submitterId: 'SES-AFF-2241',   testFiles: 6,  testFilesPassed: 5,  certifiedDate: null, notes: '1 test file rejected — ISW used (SESAC requires NWR).' },
    GMR:    { status: 'credentials', submitterId: null,             testFiles: 0,  testFilesPassed: 0,  certifiedDate: null, notes: 'Application submitted 2024-11-20. Awaiting assignment.' },
    PRS:    { status: 'certified',   submitterId: 'IPI 199900001',  testFiles: 8,  testFilesPassed: 8,  certifiedDate: '2024-09-12', notes: 'Production active.' },
    GEMA:   { status: 'conformance', submitterId: 'IPI 199900001',  testFiles: 14, testFilesPassed: 14, certifiedDate: null, notes: 'Conformance review with GEMA Frankfurt. ETA: 2 weeks.' },
    SACEM:  { status: 'testing',     submitterId: 'IPI 199900001',  testFiles: 4,  testFilesPassed: 4,  certifiedDate: null, notes: 'All test files passing. Ready for conformance request.' },
    SIAE:   { status: 'uncertified', submitterId: null,             testFiles: 0,  testFilesPassed: 0,  certifiedDate: null, notes: '' },
    JASRAC: { status: 'testing',     submitterId: 'IPI 199900001',  testFiles: 3,  testFilesPassed: 2,  certifiedDate: null, notes: '1 test file rejected — NRA encoding (require UTF-8 not Shift-JIS).' },
    SOCAN:  { status: 'certified',   submitterId: 'IPI 199900001',  testFiles: 6,  testFilesPassed: 6,  certifiedDate: '2024-10-08', notes: 'Production active.' },
    APRA:   { status: 'certified',   submitterId: 'IPI 199900001',  testFiles: 7,  testFilesPassed: 7,  certifiedDate: '2024-10-22', notes: 'Production active. PR + MR combined.' },
    STIM:   { status: 'uncertified', submitterId: null,             testFiles: 0,  testFilesPassed: 0,  certifiedDate: null, notes: '' },
    AKM:    { status: 'uncertified', submitterId: null,             testFiles: 0,  testFilesPassed: 0,  certifiedDate: null, notes: '' },
    MLC:    { status: 'certified',   submitterId: 'MLC-MEM-44218',  testFiles: 4,  testFilesPassed: 4,  certifiedDate: '2024-07-30', notes: 'Production active. ISWC + REC required.' },
    HFA:    { status: 'certified',   submitterId: 'HFA-PUB-9931',   testFiles: 3,  testFilesPassed: 3,  certifiedDate: '2024-08-19', notes: 'Production active.' },
    SAYCE:  { status: 'uncertified', submitterId: null,             testFiles: 0,  testFilesPassed: 0,  certifiedDate: null, notes: '' },
  };

  function loadState() {
    try {
      const raw = localStorage.getItem(STORAGE_KEY);
      if (raw) return { ...DEFAULT_STATE, ...JSON.parse(raw) };
    } catch (e) {}
    return DEFAULT_STATE;
  }
  function saveState(state) {
    try { localStorage.setItem(STORAGE_KEY, JSON.stringify(state)); } catch (e) {}
  }

  const STATUS_LABELS = {
    uncertified: { label: 'Not started',   color: 'var(--ink-3)',                 dot: '#cccccc' },
    credentials: { label: 'Credentials',   color: '#946800',                      dot: '#d49b2c' },
    testing:     { label: 'Testing',       color: '#1f6abd',                      dot: '#3589dd' },
    conformance: { label: 'Conformance',   color: '#7c3aed',                      dot: '#8c5be8' },
    certified:   { label: 'Certified',     color: '#1f8a4f',                      dot: '#2da763' },
    suspended:   { label: 'Suspended',     color: '#b94a4a',                      dot: '#cc5050' },
  };

  const STATUS_ORDER = ['uncertified', 'credentials', 'testing', 'conformance', 'certified'];

  // ────────────────────────────────────────────────────────────────────────
  // ROADMAP — the canonical workflow per society
  // ────────────────────────────────────────────────────────────────────────
  const RUNBOOK_STEPS = [
    {
      key: 'credentials',
      title: 'Request submitter credentials',
      description: 'Apply with the society for a submitter ID. For most CISAC societies this is your IPI; some (BMI, MLC, HFA) issue their own publisher number.',
    },
    {
      key: 'test-files',
      title: 'Generate test transmissions',
      description: 'Build CWR files using the society\'s published test bank. Validate each output passes the society\'s rule set.',
    },
    {
      key: 'submit-test',
      title: 'Submit test files',
      description: 'Send via the society\'s designated test channel (CWR Portal sandbox, SFTP test directory, or email).',
    },
    {
      key: 'review-acks',
      title: 'Review acks',
      description: 'Society returns ACK file. Every record must come back with status AS or AC. Any RJ/NP/IR triggers a fix-and-resubmit cycle.',
    },
    {
      key: 'conformance',
      title: 'Request conformance review',
      description: 'Once test files pass cleanly, request the society\'s formal conformance review. Some societies require a video call walkthrough.',
    },
    {
      key: 'certified',
      title: 'Certified — production',
      description: 'Society issues conformance letter. Production credentials assigned. Switch transport from test to production endpoints.',
    },
  ];

  function CwrCertTab() {
    const [state, setState] = useState(() => loadState());
    const [selected, setSelected] = useState(null);

    useEffect(() => { saveState(state); }, [state]);

    const profiles = window.CwrSociety?.SOCIETY_PROFILES || {};

    const ordered = useMemo(() => {
      return Object.entries(state).map(([code, st]) => ({
        code,
        ...st,
        profile: profiles[code],
      })).sort((a, b) => {
        const oa = STATUS_ORDER.indexOf(a.status);
        const ob = STATUS_ORDER.indexOf(b.status);
        if (oa !== ob) return ob - oa; // certified first
        return a.code.localeCompare(b.code);
      });
    }, [state, profiles]);

    const counts = useMemo(() => {
      const c = { certified: 0, testing: 0, conformance: 0, credentials: 0, uncertified: 0, suspended: 0 };
      ordered.forEach(o => { c[o.status] = (c[o.status] || 0) + 1; });
      return c;
    }, [ordered]);

    const advanceStatus = (code) => {
      const cur = state[code]?.status || 'uncertified';
      const idx = STATUS_ORDER.indexOf(cur);
      const next = STATUS_ORDER[Math.min(idx + 1, STATUS_ORDER.length - 1)];
      const update = { ...state[code], status: next };
      if (next === 'testing' && !update.submitterId) update.submitterId = 'IPI 199900001';
      if (next === 'certified') update.certifiedDate = new Date().toISOString().slice(0, 10);
      setState({ ...state, [code]: update });
    };

    return (
      <div>
        {/* HEADER STAT BAND */}
        <div style={{ display:'grid', gridTemplateColumns:'repeat(5, 1fr)', gap:1, background:'var(--rule)', border:'1px solid var(--rule)', marginBottom:24 }}>
          <Stat label="Total societies" value={ordered.length} />
          <Stat label="Certified"       value={counts.certified}   accent={counts.certified > 0 ? 'good' : null} />
          <Stat label="In progress"     value={counts.testing + counts.conformance + counts.credentials} accent="info" />
          <Stat label="Not started"     value={counts.uncertified} />
          <Stat label="Coverage"        value={Math.round(counts.certified / ordered.length * 100) + '%'} accent={counts.certified === ordered.length ? 'good' : 'info'} />
        </div>

        <div style={{ display:'grid', gridTemplateColumns:'1.4fr 1fr', gap:24 }}>

          {/* SOCIETY LIST */}
          <div>
            <h3 className="ff-mono upper" style={{ fontSize:11, letterSpacing:'.10em', color:'var(--ink-2)', margin:'0 0 10px', fontWeight:600 }}>Societies</h3>
            <div style={{ border:'1px solid var(--rule)' }}>
              {ordered.map((s, i) => {
                const meta = STATUS_LABELS[s.status] || STATUS_LABELS.uncertified;
                const active = selected === s.code;
                return (
                  <div key={s.code}
                    onClick={() => setSelected(active ? null : s.code)}
                    style={{
                      display:'grid', gridTemplateColumns:'24px 1fr 110px 80px 90px',
                      alignItems:'center', gap:12, padding:'12px 14px',
                      borderTop: i === 0 ? 0 : '1px solid var(--rule)',
                      background: active ? 'var(--ink-bg)' : 'var(--paper)',
                      cursor:'pointer',
                    }}>
                    <span style={{ width:10, height:10, borderRadius:'50%', background: meta.dot, display:'inline-block' }}/>
                    <div style={{ minWidth:0 }}>
                      <div style={{ fontSize:13, fontWeight:500 }}>
                        {s.profile?.name || s.code}
                        <span className="ff-mono" style={{ marginLeft:8, fontSize:10, color:'var(--ink-3)' }}>
                          {s.profile?.country || ''} · CISAC {s.profile?.cisac || '—'}
                        </span>
                      </div>
                      <div className="ff-mono" style={{ fontSize:10, color:'var(--ink-3)', marginTop:2, whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis' }}>
                        {s.notes || (s.submitterId ? s.submitterId : 'No credentials')}
                      </div>
                    </div>
                    <span className="ff-mono upper" style={{ fontSize:10, color: meta.color, letterSpacing:'.06em', fontWeight:600 }}>
                      {meta.label}
                    </span>
                    <span className="ff-mono" style={{ fontSize:11, color:'var(--ink-2)', textAlign:'right', fontVariantNumeric:'tabular-nums' }}>
                      {s.testFiles > 0 ? s.testFilesPassed + '/' + s.testFiles : '—'}
                    </span>
                    <button onClick={(e) => { e.stopPropagation(); advanceStatus(s.code); }} className="ff-mono upper" style={{
                      padding:'5px 10px', fontSize:10, letterSpacing:'.08em', fontWeight:600,
                      background: s.status === 'certified' ? 'var(--ink-bg)' : 'var(--ink)',
                      color: s.status === 'certified' ? 'var(--ink-3)' : 'var(--paper)',
                      border:0, cursor: s.status === 'certified' ? 'default' : 'pointer',
                    }}>
                      {s.status === 'certified' ? 'done' : 'advance'}
                    </button>
                  </div>
                );
              })}
            </div>
          </div>

          {/* RUNBOOK / DETAIL */}
          <div>
            <h3 className="ff-mono upper" style={{ fontSize:11, letterSpacing:'.10em', color:'var(--ink-2)', margin:'0 0 10px', fontWeight:600 }}>
              {selected ? (profiles[selected]?.name || selected) + ' — Runbook' : 'Standard runbook'}
            </h3>
            {selected && state[selected] && profiles[selected] ? (
              <RunbookDetail
                code={selected}
                state={state[selected]}
                profile={profiles[selected]}
              />
            ) : (
              <div style={{ border:'1px solid var(--rule)', padding:18 }}>
                {RUNBOOK_STEPS.map((step, i) => (
                  <div key={step.key} style={{ display:'flex', gap:14, padding:'12px 0', borderBottom: i === RUNBOOK_STEPS.length - 1 ? 0 : '1px solid var(--rule)' }}>
                    <div className="ff-mono" style={{ width:22, height:22, borderRadius:'50%', background:'var(--ink-bg)', color:'var(--ink-2)', display:'flex', alignItems:'center', justifyContent:'center', fontSize:11, fontWeight:600, flexShrink:0 }}>
                      {i + 1}
                    </div>
                    <div>
                      <div style={{ fontSize:13, fontWeight:500 }}>{step.title}</div>
                      <div style={{ fontSize:11, color:'var(--ink-3)', marginTop:3, lineHeight:1.5 }}>{step.description}</div>
                    </div>
                  </div>
                ))}
              </div>
            )}
          </div>
        </div>
      </div>
    );
  }

  function RunbookDetail({ code, state, profile }) {
    const meta = STATUS_LABELS[state.status] || STATUS_LABELS.uncertified;
    const stepIdx = STATUS_ORDER.indexOf(state.status);
    const rules = profile.rules || {};
    const ruleKeys = Object.keys(rules);

    return (
      <div style={{ border:'1px solid var(--rule)' }}>
        <div style={{ padding:'14px 16px', background:'var(--ink-bg)', borderBottom:'1px solid var(--rule)' }}>
          <div style={{ display:'flex', alignItems:'center', gap:10 }}>
            <span style={{ width:10, height:10, borderRadius:'50%', background: meta.dot }}/>
            <span className="ff-mono upper" style={{ fontSize:11, color: meta.color, letterSpacing:'.08em', fontWeight:600 }}>{meta.label}</span>
          </div>
          <div style={{ marginTop:8, fontSize:12, color:'var(--ink-2)', lineHeight:1.5 }}>
            {state.notes || 'No notes recorded.'}
          </div>
          <div style={{ display:'grid', gridTemplateColumns:'repeat(3, 1fr)', gap:0, marginTop:14 }}>
            <Mini label="Submitter ID"        value={state.submitterId || '—'} />
            <Mini label="Test files"          value={state.testFiles > 0 ? state.testFilesPassed + ' / ' + state.testFiles : '—'} />
            <Mini label="Certified"           value={state.certifiedDate || '—'} />
          </div>
        </div>

        {/* STEP TIMELINE */}
        <div style={{ padding:'14px 16px' }}>
          {RUNBOOK_STEPS.map((step, i) => {
            const done = i <= stepIdx;
            const active = i === stepIdx + 1 || (i === stepIdx && state.status !== 'certified');
            return (
              <div key={step.key} style={{ display:'flex', gap:12, padding:'10px 0' }}>
                <div className="ff-mono" style={{
                  width:22, height:22, borderRadius:'50%',
                  background: done ? 'var(--ink)' : active ? 'var(--paper)' : 'var(--ink-bg)',
                  color: done ? 'var(--paper)' : 'var(--ink-3)',
                  border: active ? '1.5px solid var(--ink)' : 0,
                  display:'flex', alignItems:'center', justifyContent:'center',
                  fontSize:11, fontWeight:600, flexShrink:0,
                }}>
                  {done ? '✓' : (i + 1)}
                </div>
                <div style={{ flex:1 }}>
                  <div style={{ fontSize:12, fontWeight:500, color: done ? 'var(--ink)' : active ? 'var(--ink)' : 'var(--ink-3)' }}>{step.title}</div>
                  {(active || done) && <div style={{ fontSize:10.5, color:'var(--ink-3)', marginTop:2, lineHeight:1.45 }}>{step.description}</div>}
                </div>
              </div>
            );
          })}
        </div>

        {/* SOCIETY-SPECIFIC RULES */}
        <div style={{ padding:'14px 16px', borderTop:'1px solid var(--rule)', background:'var(--paper)' }}>
          <div className="ff-mono upper" style={{ fontSize:10, color:'var(--ink-3)', letterSpacing:'.08em', marginBottom:8 }}>Active rules ({ruleKeys.length})</div>
          {ruleKeys.length === 0 && <div style={{ fontSize:11, color:'var(--ink-3)' }}>None — uses base CISAC spec.</div>}
          <div style={{ display:'grid', gridTemplateColumns:'repeat(2, 1fr)', gap:6 }}>
            {ruleKeys.map(k => (
              <div key={k} className="ff-mono" style={{ fontSize:10, color:'var(--ink-2)', padding:'4px 8px', background:'var(--ink-bg)' }}>
                {k}
              </div>
            ))}
          </div>
        </div>
      </div>
    );
  }

  function Stat({ label, value, accent }) {
    const color = accent === 'good' ? '#1f8a4f' : accent === 'info' ? '#1f6abd' : 'var(--ink)';
    return (
      <div style={{ background:'var(--paper)', padding:'18px 22px' }}>
        <div className="ff-mono upper" style={{ fontSize:10, color:'var(--ink-3)', letterSpacing:'.08em' }}>{label}</div>
        <div style={{ fontSize:28, marginTop:6, fontWeight:300, color, fontVariantNumeric:'tabular-nums' }}>{value}</div>
      </div>
    );
  }

  function Mini({ label, value }) {
    return (
      <div>
        <div className="ff-mono upper" style={{ fontSize:9, color:'var(--ink-3)', letterSpacing:'.06em' }}>{label}</div>
        <div className="ff-mono" style={{ fontSize:12, color:'var(--ink-2)', marginTop:4, fontVariantNumeric:'tabular-nums' }}>{value}</div>
      </div>
    );
  }

  window.CwrCertTab = CwrCertTab;
})();
