// Main DQI app — orchestrates upload, scoring, and rendering.
const { useState, useEffect, useMemo, useCallback, useRef } = React;

const GEO_TYPE_OPTIONS = ["Zone", "Region", "Branch", "N/A"];

function geoLabel(geoTypes) {
  for (const gt of geoTypes) if (gt && gt !== "N/A") return gt;
  return "Entry";
}

// --- File parsing (CSV via PapaParse, XLSX via SheetJS) ---------------------
function parseFile(file) {
  return new Promise((resolve, reject) => {
    const name = file.name.toLowerCase();
    const reader = new FileReader();
    if (name.endsWith(".csv")) {
      reader.onload = () => {
        try {
          const result = Papa.parse(reader.result, { header: true, skipEmptyLines: true, dynamicTyping: true });
          resolve(result.data);
        } catch (e) { reject(e); }
      };
      reader.readAsText(file);
    } else {
      reader.onload = () => {
        try {
          const wb = XLSX.read(new Uint8Array(reader.result), { type: "array", cellDates: true });
          const ws = wb.Sheets[wb.SheetNames[0]];
          const rows = XLSX.utils.sheet_to_json(ws, { defval: null, raw: true });
          // Convert any Date objects to ISO strings for consistency
          for (const row of rows) {
            for (const k of Object.keys(row)) {
              if (row[k] instanceof Date) row[k] = row[k].toISOString().slice(0, 10);
            }
          }
          resolve(rows);
        } catch (e) { reject(e); }
      };
      reader.readAsArrayBuffer(file);
    }
  });
}

// --- Upload zone ------------------------------------------------------------
function UploadZone({ onFiles, onDemo }) {
  const [drag, setDrag] = useState(false);
  const inputRef = useRef(null);
  return (
    <div
      className={`upload-zone ${drag ? "dragover" : ""}`}
      onDragOver={(e) => { e.preventDefault(); setDrag(true); }}
      onDragLeave={() => setDrag(false)}
      onDrop={(e) => {
        e.preventDefault(); setDrag(false);
        const files = Array.from(e.dataTransfer.files).filter((f) => /\.(xlsx|xls|csv)$/i.test(f.name));
        if (files.length) onFiles(files);
      }}
      onClick={() => inputRef.current?.click()}
    >
      <p style={{ fontWeight: 600, color: "var(--ink)" }}>Drop Excel or CSV files here, or click to browse</p>
      <p className="hint">Accepted formats: .xlsx, .xls, .csv. Multiple files supported.</p>
      <div style={{ marginTop: 12, display: "flex", justifyContent: "center", gap: 8 }}>
        <button className="primary small" onClick={(e) => { e.stopPropagation(); inputRef.current?.click(); }}>Browse files</button>
        <button className="small" onClick={(e) => { e.stopPropagation(); onDemo(); }}>Load demo data</button>
      </div>
      <input ref={inputRef} type="file" multiple accept=".xlsx,.xls,.csv" onChange={(e) => {
        const files = Array.from(e.target.files);
        if (files.length) onFiles(files);
        e.target.value = "";
      }} />
    </div>
  );
}

// --- Weight sliders (collapsed expander; AHP defaults) ----------------------
function WeightSliders({ weights, setWeights }) {
  const [open, setOpen] = useState(false);
  const total = weights.a + weights.c + weights.co + weights.t;
  const dw = (typeof DEFAULT_WEIGHTS !== "undefined" && DEFAULT_WEIGHTS) || { accuracy: 35, completeness: 30, consistency: 20, timeliness: 15 };
  const update = (key, val) => setWeights({ ...weights, [key]: Number(val) });
  const reset = () => setWeights({ a: dw.accuracy, c: dw.completeness, co: dw.consistency, t: dw.timeliness });

  const items = [
    { key: "a", label: "Accuracy" },
    { key: "c", label: "Completeness" },
    { key: "co", label: "Consistency" },
    { key: "t", label: "Timeliness" },
  ];
  return (
    <div className="card">
      <div className="disclosure">
        <div className="disclosure-summary" onClick={() => setOpen((o) => !o)}>
          <span className={`chev ${open ? "open" : ""}`}>▶</span>
          <span>Methodology — AHP-derived ACTC weights</span>
          <span style={{ marginLeft: "auto", fontSize: 12, color: total === 100 ? "var(--ink-3)" : "var(--bad)", fontWeight: 500 }}>
            {total === 100 ? `${weights.a}/${weights.c}/${weights.co}/${weights.t}` : `Total ${total}% — must equal 100%`}
          </span>
        </div>
        {open && (
          <div className="disclosure-body">
            <p className="section-caption" style={{ marginTop: 0 }}>
              Weights derived via Analytic Hierarchy Process (AHP) from SME pairwise comparisons.
              Default weighting reflects the relative importance of each dimension for MSME reporting.
              Change weights only if you want to test sensitivity.
            </p>
            <div className="weights-grid">
              {items.map((it) => (
                <div className="weight-item" key={it.key}>
                  <div className="weight-label-row">
                    <span className="weight-label">{it.label}</span>
                    <span className="weight-value">{weights[it.key]}%</span>
                  </div>
                  <input type="range" min="0" max="100" value={weights[it.key]} onChange={(e) => update(it.key, e.target.value)} />
                </div>
              ))}
            </div>
            <div className={`weight-total ${total === 100 ? "ok" : "bad"}`}>
              <span>Total: <strong>{total}%</strong> {total === 100 ? "" : "— must equal 100%"}</span>
              <button className="small" onClick={reset}>Reset to AHP defaults ({dw.accuracy}/{dw.completeness}/{dw.consistency}/{dw.timeliness})</button>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

// --- Detection row ----------------------------------------------------------
// One row per uploaded file. Shows auto-detected profile + geography with
// a status pill, and lets the user override any field inline. The whole
// batch is committed by the single "Confirm all & score" button in App.
function DetectionRow({ entry, onChange, onRemove }) {
  const profileOptions = [...getProfileNames(), "Default"];
  const isDefault = entry.profile_name === "Default";
  const isAuto = !!entry.auto;
  const status = isDefault
    ? { dot: "var(--warn)", text: "No profile match — using Default" }
    : isAuto
      ? { dot: "var(--good)", text: "Auto-detected" }
      : { dot: "var(--accent)", text: "Manual override" };

  const setProfile = (v) => onChange(entry.name, { profile_name: v, auto: false });
  const setGeoType = (v) => onChange(entry.name, { geo_type: v, auto: false });
  const setLabel = (v) => onChange(entry.name, { label: v, auto: false });

  return (
    <div className="file-config">
      <div className="file-config-header">
        <div className="file-config-name">
          <span className="icon-doc">{entry.name.toLowerCase().endsWith(".csv") ? "CSV" : "XLS"}</span>
          {entry.name}
          <span className="hint" style={{ color: "var(--ink-3)", fontSize: 12, fontWeight: 400 }}>
            ({entry.df.length.toLocaleString()} rows × {entry.df[0] ? Object.keys(entry.df[0]).length : 0} cols)
          </span>
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
          <span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontSize: 12, color: "var(--ink-2)" }}>
            <span style={{ display: "inline-block", width: 8, height: 8, borderRadius: "50%", background: status.dot }}></span>
            {status.text}
          </span>
          <button className="small ghost" onClick={() => onRemove(entry.name)}>Remove</button>
        </div>
      </div>

      <div className="file-config-form">
        <div className="field">
          <label>Profile</label>
          <select value={entry.profile_name} onChange={(e) => setProfile(e.target.value)}>
            {profileOptions.map((p) => <option key={p} value={p}>{p}</option>)}
          </select>
        </div>
        <div className="field">
          <label>Geography Type</label>
          <select value={entry.geo_type} onChange={(e) => setGeoType(e.target.value)}>
            {GEO_TYPE_OPTIONS.map((g) => <option key={g} value={g}>{g}</option>)}
          </select>
        </div>
        <div className="field">
          <label>Geography Label</label>
          <input type="text" value={entry.label || ""} disabled={entry.geo_type === "N/A"} onChange={(e) => setLabel(e.target.value)} placeholder={entry.geo_type === "N/A" ? "Not applicable" : "e.g. North, Mumbai"} />
        </div>
      </div>
    </div>
  );
}

// --- Score-card per file ----------------------------------------------------
function ScoreCard({ entry, weights, totalOk, onClearHistory, cloudOnline, history }) {
  const [open, setOpen] = useState(false);
  const { df, profile, scores, dqi, filename, zone_label, geo_type, detailed } = entry;
  const dqiVal = dqi ?? 0;
  const dqiCls = dqiVal >= 90 ? "good" : dqiVal >= 75 ? "warn" : "bad";

  const nullCounts = useMemo(() => nullCountsByColumn(df), [df]);
  const nullEntries = Object.entries(nullCounts).filter(([, v]) => v > 0);

  const hist = history || [];
  const xLabels = hist.map((h) => h.uploaded_at.slice(5, 16));

  const isZoned = geo_type && geo_type !== "N/A";
  const clearLabel = isZoned
    ? `Clear trend history for ${geo_type}: ${zone_label}`
    : `Clear history for ${filename}`;

  return (
    <div className="score-card">
      <div className="score-card-header" onClick={() => setOpen((o) => !o)}>
        <div className="score-card-title">
          <span className={`chev ${open ? "open" : ""}`}>▶</span>
          {geo_type !== "N/A" && <GeoTag geoType={geo_type} />}
          <span>{zone_label}</span>
        </div>
        <div className="score-card-meta">
          {scores && <span className={`dqi-pill ${dqiCls}`}>DQI {dqiVal.toFixed(1)}%</span>}
        </div>
      </div>
      {open && (
        <div className="score-card-body">
          <div className="kv-row"><span className="k">File</span><span className="v"><code className="fname">{filename}</code></span></div>
          <div className="kv-row"><span className="k">Geography Type</span><span className="v">{geo_type}</span></div>
          <div className="kv-row"><span className="k">Rows × Columns</span><span className="v">{df.length.toLocaleString()} × {df[0] ? Object.keys(df[0]).length : 0}</span></div>

          {totalOk && scores ? (
            <div className="sub-section">
              <h4>ACTC Dimension Scores (this upload)</h4>
              <table className="dqi-table">
                <thead>
                  <tr>
                    <th>Dimension</th>
                    <th>Score (%)</th>
                    <th>Weight (%)</th>
                    <th>Check</th>
                  </tr>
                </thead>
                <tbody>
                  {DIMENSIONS.map((dim, i) => {
                    const wgt = [weights.a, weights.c, weights.co, weights.t][i];
                    const dimChecks = profile.checks[dim] || [];
                    const ck = dimChecks.length > 1
                      ? `${dimChecks.length} checks — avg of all per-check scores`
                      : (dimChecks[0]?.description || "");
                    return (
                      <tr key={dim}>
                        <td>{DIM_LABELS[dim]}</td>
                        <td className="num"><HeatCell value={scores[dim]} decimals={2} /></td>
                        <td className="num">{wgt}</td>
                        <td>{ck}</td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
              <div className="big-metric">
                <div>
                  <div className="label">Overall DQI Score</div>
                  <div className="value">{dqiVal.toFixed(2)}<span className="unit">%</span></div>
                </div>
              </div>
            </div>
          ) : (
            <Banner kind="info">Fix the weights above (must sum to 100%) to see the DQI score.</Banner>
          )}

          {detailed && totalOk && (
            <div className="sub-section">
              <Disclosure title="All checks (per dimension)">
                <p className="section-caption" style={{ marginTop: 0 }}>
                  Each dimension’s score is the equal-weighted average of its checks.
                  Pass ≥ {CHECK_BAND_PASS.toFixed(0)}%, Warn ≥ {CHECK_BAND_WARN.toFixed(0)}%, Fail &lt; {CHECK_BAND_WARN.toFixed(0)}%.
                </p>
                {DIMENSIONS.map((dim) => {
                  const block = detailed[dim] || { score: 0, checks: [] };
                  const n = block.checks.length;
                  return (
                    <div key={dim} className="sub-section">
                      <div style={{ fontSize: 13, color: "var(--ink-2)", fontWeight: 600, marginBottom: 6 }}>
                        {DIM_LABELS[dim]} — {n} check{n === 1 ? "" : "s"}, avg {block.score.toFixed(1)}%
                      </div>
                      {n === 0 ? (
                        <div style={{ color: "var(--ink-3)", fontSize: 13, fontStyle: "italic" }}>(no checks defined for this dimension)</div>
                      ) : (
                        <table className="dqi-table">
                          <thead>
                            <tr>
                              <th style={{ width: 32 }}></th>
                              <th>Check</th>
                              <th>Type</th>
                              <th>Score (%)</th>
                            </tr>
                          </thead>
                          <tbody>
                            {block.checks.map((c, i) => {
                              const st = checkStatus(c.score);
                              return (
                                <tr key={i}>
                                  <td style={{ textAlign: "center", color: st.color, fontWeight: 700 }}>{st.icon}</td>
                                  <td>{c.description}</td>
                                  <td><code className="fname">{c.type}</code></td>
                                  <td className="num"><HeatCell value={c.score} decimals={1} /></td>
                                </tr>
                              );
                            })}
                          </tbody>
                        </table>
                      )}
                    </div>
                  );
                })}
              </Disclosure>
            </div>
          )}

          <div className="sub-section">
            <Disclosure title="Null Values per Column">
              {nullEntries.length === 0 ? (
                <div style={{ color: "var(--ink-3)", fontSize: 13 }}>No nulls found in this file. ✨</div>
              ) : (
                <table className="dqi-table">
                  <thead><tr><th>Column</th><th>Null Count</th></tr></thead>
                  <tbody>
                    {nullEntries.map(([col, cnt]) => (
                      <tr key={col}><td>{col.replace(/_/g, " ")}</td><td className="num">{cnt}</td></tr>
                    ))}
                  </tbody>
                </table>
              )}
            </Disclosure>
          </div>

          <div className="sub-section">
            <Disclosure title="Historical Trend and Data">
              {hist.length > 1 ? (
                <>
                  <h4>Upload History</h4>
                  <div style={{ overflowX: "auto" }}>
                    <table className="dqi-table">
                      <thead>
                        <tr>
                          <th>Uploaded At</th>
                          <th>Profile</th>
                          <th>Geography</th>
                          <th>Accuracy %</th>
                          <th>Completeness %</th>
                          <th>Consistency %</th>
                          <th>Timeliness %</th>
                          <th>DQI %</th>
                        </tr>
                      </thead>
                      <tbody>
                        {hist.map((h, i) => (
                          <tr key={i}>
                            <td>{h.uploaded_at}</td>
                            <td>{h.profile}</td>
                            <td>{h.geography || "—"}</td>
                            <td className="num"><HeatCell value={h.accuracy_score} /></td>
                            <td className="num"><HeatCell value={h.completeness_score} /></td>
                            <td className="num"><HeatCell value={h.consistency_score} /></td>
                            <td className="num"><HeatCell value={h.timeliness_score} /></td>
                            <td className="num"><HeatCell value={h.dqi_score} /></td>
                          </tr>
                        ))}
                      </tbody>
                    </table>
                  </div>
                  <div className="sub-section">
                    <div className="chart-title">Overall DQI Score Trend</div>
                    <LineChart xLabels={xLabels} series={[{ label: "DQI", values: hist.map((h) => h.dqi_score) }]} />
                  </div>
                  <div className="sub-section">
                    <div className="chart-title">ACTC Dimensions Trend</div>
                    <LineChart xLabels={xLabels} series={DIMENSIONS.map((d) => ({ label: DIM_LABELS[d], values: hist.map((h) => h[`${d}_score`]) }))} />
                  </div>
                </>
              ) : (
                <Banner kind="info">Upload this {isZoned ? `${geo_type.toLowerCase()}` : "file"} more than once to see historical trends.</Banner>
              )}
              <div style={{ marginTop: 10 }}>
                <button
                  className="small danger"
                  onClick={() => onClearHistory(entry)}
                  disabled={!cloudOnline}
                  title={!cloudOnline ? "Connect to the cloud database to enable" : ""}
                >{clearLabel}</button>
              </div>
            </Disclosure>
          </div>
        </div>
      )}
    </div>
  );
}

// --- Comparison block (per profile, when ≥2 confirmed entries) -------------
function ComparisonBlock({ profileName, entries }) {
  const geoWord = geoLabel(entries.map((e) => e.geo_type));
  const zones = entries.map((e) => e.zone_label);
  const dqiScores = entries.map((e) => {
    const v = Number(e.dqi);
    return Number.isFinite(v) ? Number(v.toFixed(2)) : 0;
  });
  const dimSeries = DIMENSIONS.map((d) => ({
    label: DIM_LABELS[d],
    values: entries.map((e) => {
      const v = Number(e.scores?.[d]);
      return Number.isFinite(v) ? Number(v.toFixed(2)) : 0;
    }),
  }));
  return (
    <div className="card">
      <h3 className="section-title">{profileName} — {geoWord}s</h3>

      <div className="compare-grid">
        <div>
          <div className="chart-title">Overall DQI Score by {geoWord}</div>
          <BarChart data={zones.map((z, i) => ({ label: z, value: dqiScores[i] }))} />
        </div>
        <div>
          <div className="chart-title">ACTC Dimension Scores by {geoWord}</div>
          <GroupedBarChart groups={DIMENSIONS.map((d) => DIM_LABELS[d])} series={zones.map((z, i) => ({ label: z, values: DIMENSIONS.map((d) => entries[i].scores[d]) }))} />
        </div>
      </div>

      <div className="sub-section" style={{ marginTop: 16 }}>
        <div className="chart-title">{geoWord} Comparison Summary</div>
        <table className="dqi-table">
          <thead>
            <tr>
              <th>{geoWord}</th>
              <th>Accuracy %</th>
              <th>Completeness %</th>
              <th>Consistency %</th>
              <th>Timeliness %</th>
              <th>DQI %</th>
            </tr>
          </thead>
          <tbody>
            {entries.map((e, i) => (
              <tr key={i}>
                <td>{e.zone_label}</td>
                <td className="num"><HeatCell value={e.scores.accuracy} /></td>
                <td className="num"><HeatCell value={e.scores.completeness} /></td>
                <td className="num"><HeatCell value={e.scores.consistency} /></td>
                <td className="num"><HeatCell value={e.scores.timeliness} /></td>
                <td className="num"><HeatCell value={e.dqi} /></td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

Object.assign(window, { UploadZone, WeightSliders, DetectionRow, ScoreCard, ComparisonBlock, parseFile, geoLabel, GEO_TYPE_OPTIONS });
