/* ============================================================
   Report panel + assessor cards + score + detail drawer
   ============================================================ */

const StatusIcon = ({ status, size }) => {
  const s = PC_STATUS[status] || PC_STATUS.unknown;
  return <span className={`pc-status-ico pc-status-${s.cls}`} style={size ? { width: size, height: size } : null}>{s.glyph}</span>;
};

const StatusPill = ({ status }) => {
  const s = PC_STATUS[status] || PC_STATUS.unknown;
  return <span className={`pc-pill pc-pill-${s.cls}`}>{s.glyph}{s.label}</span>;
};

const ConfBadge = ({ level }) => {
  if (!level) return null;
  const n = PC_CONF_LEVEL[level] || 0;
  return (
    <span className={`conf pc-conf-${level}`}>
      <span className="pc-conf-dots">{[0, 1, 2].map(i => <i key={i} className={i < n ? 'on' : ''} />)}</span>
      {level}
    </span>
  );
};

function verdictFor(score) {
  if (score == null) return 'Awaiting assessment';
  if (score >= 80) return 'Strong prospect';
  if (score >= 65) return 'Promising';
  if (score >= 50) return 'Marginal';
  return 'Weak prospect';
}

const ScoreDial = ({ score, status }) => {
  const r = 32, c = 2 * Math.PI * r;
  const pct = score == null ? 0 : score / 100;
  const col = { green: 'var(--st-green)', amber: 'var(--st-amber)', red: 'var(--st-red)', unknown: 'var(--st-unknown)' }[status] || 'var(--st-unknown)';
  return (
    <div className="pc-score-dial">
      <svg width="76" height="76">
        <circle cx="38" cy="38" r={r} fill="none" stroke="var(--ls-bone-p1)" strokeWidth="7" />
        <circle cx="38" cy="38" r={r} fill="none" stroke={col} strokeWidth="7" strokeLinecap="round"
          strokeDasharray={`${c * pct} ${c}`} strokeDashoffset="0"
          style={{ transition: 'stroke-dasharray .6s var(--ease-out)' }}
          {...(score == null ? { strokeDasharray: '3 6', stroke: 'var(--st-unknown)' } : {})} />
      </svg>
      <div className="val">
        <span className="num">{score == null ? '–' : score}</span>
        <span className="max">/ 100</span>
      </div>
    </div>
  );
};

const ValueRows = ({ values }) => {
  const entries = Object.entries(values || {});
  if (!entries.length) return null;
  return (
    <div className="pc-values">
      {entries.map(([k, v]) => (
        <div className="pc-value-row" key={k}><span className="k">{k}</span><span className="v">{v}</span></div>
      ))}
    </div>
  );
};

const AssessorCard = ({ result, onOpen, clickable }) => {
  const meta = PC_ASSESSOR_META[result.assessor_key] || { name: result.assessor_key };
  const isUnknown = result.status === 'unknown';
  return (
    <div className={`pc-card ${isUnknown ? 'is-unknown' : ''} ${clickable ? 'clickable' : ''}`}
         onClick={clickable ? () => onOpen(result) : undefined}>
      <div className="pc-card-top">
        <StatusIcon status={result.status} />
        <div className="pc-card-main">
          <div className="pc-card-key">{meta.name}</div>
          <div className="pc-card-headline">{result.headline}</div>
        </div>
        {clickable && !isUnknown && <span className="pc-chevron">{PCI.chevron}</span>}
      </div>

      {!isUnknown && <ValueRows values={result.values} />}

      {isUnknown ? (
        <div className="pc-pending">{PCI.clock}<span>Not yet implemented — this check will fill in automatically once the assessor is online.</span></div>
      ) : (
        <div className="pc-source-line">
          <span>{result.source}</span>
          {result.source_retrieved_at && <span>· retrieved {result.source_retrieved_at}</span>}
          <ConfBadge level={result.confidence} />
        </div>
      )}
    </div>
  );
};

const ReportSection = ({ section, results, onOpen, clickable, headerAction }) => {
  const inSection = section.keys
    .map(k => results.find(r => r.assessor_key === k))
    .filter(Boolean);
  if (!inSection.length) return null;
  const pending = inSection.filter(r => r.status === 'unknown').length;
  return (
    <div className="pc-section">
      <div className="pc-section-head">
        <img src={`assets/icons/${section.icon}`} alt="" />
        <h4>{section.label}</h4>
        <span className="count">{pending ? `${pending} pending` : `${inSection.length} checked`}</span>
        {headerAction && <span className="pc-section-action">{headerAction}</span>}
      </div>
      {inSection.map(r => <AssessorCard key={r.assessor_key} result={r} onOpen={onOpen} clickable={clickable} />)}
    </div>
  );
};

/** Compact on/off pill — used by section headers (e.g. "Show on map"). */
const SectionToggle = ({ on, disabled, onChange, label }) => (
  <button type="button"
          className={`pc-section-toggle ${on ? 'is-on' : ''} ${disabled ? 'is-disabled' : ''}`}
          aria-pressed={on}
          aria-disabled={disabled}
          disabled={disabled}
          onClick={() => !disabled && onChange(!on)}>
    <span className="track"><span className="thumb" /></span>
    <span className="lbl">{label}</span>
  </button>
);

const EmptyPanel = () => (
  <div className="pc-panel-empty">
    <img src="assets/icons/Icon_Location.png" alt="" />
    <h3>No site selected</h3>
    <p>Draw a boundary or search an address to run a fast-screen assessment. Or pick a site from the pipeline.</p>
  </div>
);

const PC_LOADING_STEPS = [
  'Matching boundary to LINZ parcels',
  'Resolving land tenure & titles',
  'Querying grid proximity',
  'Modelling solar resource',
  'Reading terrain & slope',
  'Checking planning constraints',
];

/* Inline toast. Accepts a string (simple notification) or an object
   { msg, kind, actions: [{label, primary, onClick}] } for action toasts
   (e.g. Save / Discard after a boundary edit). */
const Toast = ({ msg }) => {
  if (!msg) return null;
  const t = typeof msg === 'string' ? { msg } : msg;
  return (
    <div className={`pc-toast ${t.kind || ''}`}>
      <span className="pc-toast-msg">{t.msg}</span>
      {(t.actions || []).map((a, i) => (
        <button key={i} className={`pc-toast-btn ${a.primary ? 'is-primary' : ''}`} onClick={a.onClick}>{a.label}</button>
      ))}
    </div>
  );
};

const ErrorPanel = ({ error, onClose }) => (
  <div className="pc-panel-empty">
    <img src="assets/icons/Icon_Construction.png" alt="" />
    <h3>Assessment failed</h3>
    <p style={{ wordBreak: 'break-word' }}>{error || 'The backend could not complete the assessment.'}</p>
    <p>Check that <code>Start-Prospecting.ps1</code> launched the backend on port 8766, then try again.</p>
    <button className="pc-btn pc-btn-outline" onClick={onClose} style={{ marginTop: 12 }}>Close</button>
  </div>
);

const LoadingPanel = ({ step }) => (
  <div className="pc-loading">
    <div className="pc-loading-head">
      <div className="spin" />
      <h3>Running assessment</h3>
      <p>Fast-screening the boundary against every assessor.</p>
    </div>
    <div className="pc-loading-list">
      {PC_LOADING_STEPS.map((label, i) => (
        <div key={i} className={`pc-loading-item ${i < step ? 'done' : i === step ? 'active' : ''}`}>
          <span className="tick">
            {i < step ? <span style={{ color: 'var(--st-green-fg)' }}>{PCI.check}</span>
              : i === step ? <span className="dot-spin" />
              : <span style={{ width: 14, height: 14, borderRadius: '50%', border: '2px solid var(--border-strong)' }} />}
          </span>
          <span>{label}</span>
        </div>
      ))}
    </div>
  </div>
);

const ReportPanel = ({ site, onClose, onExport, onOpenAssessor, clickable, gridSectionToggle }) => {
  const pending = site.assessors.filter(a => a.status === 'unknown').length;
  const total = site.assessors.length;
  return (
    <>
      <div className="pc-rep-head">
        <div className="pc-rep-eyebrow">
          <span className="eyebrow">Site report · {site.id}</span>
          <button className="pc-rep-close" onClick={onClose} aria-label="Close report">{PCI.close}</button>
        </div>
        <h2 className="pc-rep-title">{site.name}</h2>
        <div className="pc-rep-sub">
          <span>{site.address}</span>
        </div>
        <div className="pc-rep-sub" style={{ marginTop: 6 }}>
          <span><b>{site.area_ha} ha</b> · {site.shape_descriptor}</span>
        </div>
      </div>

      <div className="pc-score">
        <ScoreDial score={site.overall_score} status={site.overall_status} />
        <div className="pc-score-meta">
          <div className="label">Fast-screen score</div>
          <div className="verdict">{verdictFor(site.overall_score)}</div>
          <div style={{ display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' }}>
            <StatusPill status={site.overall_status} />
            <span className="pc-score-note">{pending} of {total} assessors pending — score reflects geometry & tenure only.</span>
          </div>
        </div>
      </div>

      <div className="pc-rep-body">
        {PC_SECTIONS.map(sec => {
          const headerAction =
            sec.id === 'grid' && gridSectionToggle ? (
              <SectionToggle
                on={gridSectionToggle.on}
                disabled={!gridSectionToggle.canEnable}
                onChange={gridSectionToggle.onChange}
                label="Show on map"
              />
            ) : null;
          return (
            <ReportSection key={sec.id} section={sec} results={site.assessors}
                           onOpen={onOpenAssessor} clickable={clickable}
                           headerAction={headerAction} />
          );
        })}
        <div style={{ height: 4 }} />
      </div>

      <div className="pc-rep-foot">
        <button className="pc-btn pc-btn-primary pc-btn-block" onClick={onExport}>{PCI.download}Export report</button>
      </div>
    </>
  );
};

const DetailDrawer = ({ assessor, open, onClose, width }) => {
  const a = assessor;
  const meta = a ? (PC_ASSESSOR_META[a.assessor_key] || { name: a.assessor_key }) : {};
  return (
    <>
      <div className={`pc-drawer-scrim ${open ? 'open' : ''}`} onClick={onClose} />
      <aside className={`pc-drawer ${open ? 'open' : ''}`} aria-hidden={!open} style={width ? { width } : null}>
        {a && (
          <>
            <div className="pc-drawer-head">
              <StatusIcon status={a.status} size={34} />
              <div>
                <div className="key">{meta.name}</div>
                <h3>{a.headline}</h3>
                <StatusPill status={a.status} />
              </div>
              <button className="pc-drawer-close" onClick={onClose} aria-label="Close detail">{PCI.close}</button>
            </div>
            <div className="pc-drawer-body">
              <h5>What this checks</h5>
              <p className="pc-detail-prose">{meta.about}</p>

              {Object.keys(a.values || {}).length > 0 && (
                <>
                  <h5>Reported values</h5>
                  <div className="pc-detail-values">
                    {Object.entries(a.values).map(([k, v]) => (
                      <div className="pc-value-row" key={k}><span className="k">{k}</span><span className="v">{v}</span></div>
                    ))}
                  </div>
                </>
              )}

              <h5>Sources</h5>
              <div className="pc-detail-meta">
                <div className="row"><span>Status</span><b>{(PC_STATUS[a.status] || {}).label}</b></div>
                <div className="row"><span>Data source</span><b>{a.source || 'Not yet connected'}</b></div>
                <div className="row"><span>Retrieved</span><b>{a.source_retrieved_at || '—'}</b></div>
                <div className="row"><span>Confidence</span><b style={{ textTransform: 'capitalize' }}>{a.confidence || 'n/a'}</b></div>
              </div>
            </div>
          </>
        )}
      </aside>
    </>
  );
};

Object.assign(window, {
  StatusIcon, StatusPill, ConfBadge, ScoreDial, AssessorCard, ReportSection,
  SectionToggle, ReportPanel, LoadingPanel, EmptyPanel, ErrorPanel, DetailDrawer,
  Toast, verdictFor, PC_LOADING_STEPS,
});
