/* global React, Icon, Modal, SECTORS, sectorById, sectorLabel, projectName, ProgrammeGantt */
const { useState: useStatePD2, useMemo: useMemoPD2 } = React;

// ==================== PROGRAMME DETAIL ====================
function ProgrammeDetail({ t, lang, selectedProgramme, onOpen, onBack }) {
  const { programmes, loading: lprogLoading, refresh: refreshProgrammes, realtime: progRealtime } = window.melr.usePrograms();
  const { projects: liveProjects, loading: lpLoading } = window.melr.useProjects();
  // Pull ALL org indicators (no project filter) — we'll narrow client-side
  // to the projects attached to this programme.
  const { data: allIndicators, loading: lindLoading } = window.melr.useIndicators();
  const { currency } = window.melr.useCurrency();
  const LiveBadge = window.melr.LiveBadge;
  const fmtM = (v) => window.melr.formatMoney(v, currency, lang);
  const fmtP = (v, src) => window.melr.formatAmount(v, src || "EUR", currency, lang);

  const [tab, setTab] = useStatePD2("overview");
  const [editOpen, setEditOpen] = useStatePD2(false);
  const [deleteConfirm, setDeleteConfirm] = useStatePD2(false);
  const [busy, setBusy] = useStatePD2(false);
  const [err, setErr] = useStatePD2(null);

  const programme = useMemoPD2(
    () => (programmes || []).find((p) => p.id === selectedProgramme),
    [programmes, selectedProgramme]
  );

  // Projects attached to this programme
  const attachedProjects = useMemoPD2(
    () => (liveProjects || []).filter((p) => p.programmeId === selectedProgramme),
    [liveProjects, selectedProgramme]
  );

  // Indicator rollup: every indicator of every project attached to this
  // programme, normalized into a flat table with project code, latest
  // value, status, etc. — same shape the existing PDIndicators table
  // expects (so the visual is consistent).
  const indicatorRollup = useMemoPD2(() => {
    const projectUuids = new Set(attachedProjects.map((p) => p.uuid).filter(Boolean));
    const codeByUuid   = new Map(attachedProjects.map((p) => [p.uuid, p.id]));
    return (allIndicators || [])
      .filter((i) => projectUuids.has(i.project_id))
      .map((i) => {
        const b = Number(i.baseline) || 0;
        const tg = Number(i.target)  || 0;
        const values = (i.indicator_values || [])
          .slice()
          .sort((a, b) => (a.period_start || "").localeCompare(b.period_start || ""));
        const actual = values.length > 0 ? Number(values[values.length - 1].value) || 0 : b;
        const status = values.length > 0
          ? (values[values.length - 1].status || "pending")
          : "pending";
        const trend = values.length > 0
          ? [b, ...values.map((v) => Number(v.value) || 0)]
          : [b, b];
        // Progress towards target — handles inverted indicators (where
        // a lower value is better) by checking if the target is below baseline.
        const inverted = tg < b;
        let pct;
        if (inverted) {
          // From baseline going DOWN towards target
          pct = b === tg ? 0 : Math.round(((b - actual) / (b - tg)) * 100);
        } else {
          pct = tg === b ? 0 : Math.round(((actual - b) / (tg - b)) * 100);
        }
        pct = Math.max(0, Math.min(150, pct));
        return {
          uuid: i.id,
          code: i.code,
          level: (i.level || "outcome").toLowerCase(),
          name: lang === "en" ? (i.name_en || i.name_fr) : i.name_fr,
          unit: i.unit || "",
          baseline: b,
          target: tg,
          actual,
          status,
          trend,
          pct,
          projectCode: codeByUuid.get(i.project_id) || "—",
        };
      })
      .sort((a, b) => {
        // Outcome > Output > Impact > others
        const order = { outcome: 0, output: 1, impact: 2 };
        const ao = order[a.level] != null ? order[a.level] : 9;
        const bo = order[b.level] != null ? order[b.level] : 9;
        return ao - bo || a.code.localeCompare(b.code);
      });
  }, [allIndicators, attachedProjects, lang]);

  // Indicator rollup summary
  const indicatorStats = useMemoPD2(() => {
    const total = indicatorRollup.length;
    const onTarget = indicatorRollup.filter((i) => i.status === "ok").length;
    const watch    = indicatorRollup.filter((i) => i.status === "warn").length;
    const risk     = indicatorRollup.filter((i) => i.status === "risk").length;
    const pending  = indicatorRollup.filter((i) => i.status === "pending").length;
    const avgPct   = total ? Math.round(indicatorRollup.reduce((s, i) => s + i.pct, 0) / total) : 0;
    return { total, onTarget, watch, risk, pending, avgPct };
  }, [indicatorRollup]);

  // Aggregate KPIs (EUR pivot for multi-currency)
  const kpis = useMemoPD2(() => {
    if (!programme) return null;
    const totalBudgetEur = attachedProjects.reduce(
      (s, p) => s + window.melr.convertToEur(p.budget || 0, p.nativeCurrency || "EUR"), 0
    );
    const totalDisbEur = attachedProjects.reduce(
      (s, p) => s + window.melr.convertToEur(p.disbursed || 0, p.nativeCurrency || "EUR"), 0
    );
    const totalSites = attachedProjects.reduce((s, p) => s + (p.sites || 0), 0);
    const totalIndic = attachedProjects.reduce((s, p) => s + (p.indic || 0), 0);
    const avgProgress = attachedProjects.length
      ? Math.round(attachedProjects.reduce((s, p) => s + (p.progress || 0), 0) / attachedProjects.length)
      : 0;
    return { totalBudgetEur, totalDisbEur, totalSites, totalIndic, avgProgress };
  }, [programme, attachedProjects]);

  // Activity feed — derived from existing rows (programme + projects +
  // indicators). For a proper audit log (per-field, per-user) we would
  // need a dedicated Postgres trigger setup; this v1 surfaces what we
  // can read today.
  //
  // IMPORTANT: this hook MUST be declared BEFORE the early returns below,
  // otherwise the hook call order would change between renders and React
  // would throw "Rendered more hooks than during the previous render".
  const activityFeed = useMemoPD2(() => {
    if (!programme) return [];
    const events = [];
    if (programme.created_at) {
      events.push({
        ts: programme.created_at,
        type: "programme_created",
        label: lang === "fr" ? "Programme créé" : "Programme created",
        detail: programme.code + " — " + (lang === "en" ? (programme.name_en || programme.name_fr) : programme.name_fr),
        icon: "✦",
        color: "var(--accent)",
      });
    }
    if (programme.updated_at && programme.updated_at !== programme.created_at) {
      events.push({
        ts: programme.updated_at,
        type: "programme_updated",
        label: lang === "fr" ? "Programme modifié" : "Programme updated",
        detail: lang === "fr" ? "Métadonnées du programme mises à jour" : "Programme metadata updated",
        icon: "✎",
        color: "var(--text-faint)",
      });
    }
    (attachedProjects || []).forEach((p) => {
      if (p.created_at) {
        events.push({
          ts: p.created_at,
          type: "project_attached",
          label: lang === "fr" ? "Projet rattaché" : "Project attached",
          detail: p.id + " — " + projectName(p, lang),
          icon: "+",
          color: "var(--green)",
        });
      }
    });
    // Indicators created within attached projects — already filtered to this programme
    (allIndicators || [])
      .filter((i) => (attachedProjects || []).some((p) => p.uuid === i.project_id))
      .forEach((i) => {
        if (i.created_at) {
          events.push({
            ts: i.created_at,
            type: "indicator_created",
            label: lang === "fr" ? "Indicateur créé" : "Indicator created",
            detail: i.code + " — " + (lang === "en" ? (i.name_en || i.name_fr) : i.name_fr),
            icon: "📊",
            color: "var(--violet)",
          });
        }
        // Indicator values entered — show the latest few per indicator
        const vals = (i.indicator_values || [])
          .filter((v) => v.period_start) // ignore null period (legacy)
          .slice(-3);
        vals.forEach((v) => {
          // Use period_start as the activity date proxy (we don't have created_at for values in the current select)
          events.push({
            ts: v.period_start,
            type: "indicator_value",
            label: lang === "fr" ? "Mesure saisie" : "Measurement entered",
            detail: i.code + " : " + v.value + (i.unit ? " " + i.unit : "") + (v.status ? " (" + v.status + ")" : ""),
            icon: "▶",
            color: v.status === "ok" ? "var(--green)" : v.status === "warn" ? "var(--amber)" : v.status === "risk" ? "var(--red)" : "var(--text-faint)",
          });
        });
      });
    // Sort by timestamp descending (most recent first)
    return events.sort((a, b) => String(b.ts).localeCompare(String(a.ts)));
  }, [programme, attachedProjects, allIndicators, lang]);

  if (lprogLoading || lpLoading) {
    return <div className="page"><div className="page-body" style={{ padding: 40 }}>{lang === "fr" ? "Chargement…" : "Loading…"}</div></div>;
  }
  if (!programme) {
    return (
      <div className="page">
        <div className="page-body" style={{ padding: 40, textAlign: "center" }}>
          <div className="text-faint" style={{ fontSize: 14, marginBottom: 10 }}>
            {lang === "fr" ? "Programme introuvable." : "Programme not found."}
          </div>
          <button className="btn sm" onClick={onBack}>
            <Icon.chevronLeft /> {lang === "fr" ? "Retour aux programmes" : "Back to programmes"}
          </button>
        </div>
      </div>
    );
  }

  const sector = sectorById(programme.sector_id);
  const displayName = lang === "en" ? (programme.name_en || programme.name_fr) : programme.name_fr;

  const TABS = [
    { k: "overview",   l: lang === "fr" ? "Vue d'ensemble" : "Overview" },
    { k: "projects",   l: lang === "fr" ? "Projets rattachés" : "Attached projects", c: attachedProjects.length },
    { k: "indicators", l: lang === "fr" ? "Indicateurs consolidés" : "Consolidated indicators", c: indicatorRollup.length },
    { k: "gantt",      l: lang === "fr" ? "Gantt consolidé" : "Consolidated Gantt" },
    { k: "activity",   l: lang === "fr" ? "Activité" : "Activity", c: activityFeed.length },
  ];

  const onDelete = async () => {
    setBusy(true); setErr(null);
    try {
      await window.melr.deleteProgramme(programme.id);
      setDeleteConfirm(false);
      onBack && onBack();
    } catch (e) {
      setErr(e.message);
    } finally {
      setBusy(false);
    }
  };

  return (
    <div className="page pd-page">
      {/* Header */}
      <div className="pd-header">
        <button className="pd-back" onClick={onBack}>
          <Icon.chevronLeft />
          <span>{lang === "fr" ? "Programmes" : "Programmes"}</span>
        </button>
        <div className="pd-title-row">
          <div style={{ flex: 1, minWidth: 0 }}>
            <div className="row gap-sm" style={{ marginBottom: 6 }}>
              <span className="mono text-faint" style={{ fontSize: 11.5 }}>{programme.code}</span>
              <span className="dotsep"></span>
              <span className="sector-chip"
                style={{ background: sector.bg, color: sector.color, borderColor: sector.color }}>
                {sectorLabel(sector, lang)}
              </span>
              <span className="dotsep"></span>
              <span className="pill">{attachedProjects.length} {lang === "fr" ? (attachedProjects.length > 1 ? "projets" : "projet") : (attachedProjects.length > 1 ? "projects" : "project")}</span>
              {programme.currency && programme.currency !== currency && (
                <>
                  <span className="dotsep"></span>
                  <span style={{
                    padding: "2px 8px", borderRadius: 999, background: "var(--bg-sunken)",
                    color: "var(--text-faint)", fontSize: 11, fontWeight: 500,
                  }} title={lang === "fr" ? "Devise native du programme" : "Native programme currency"}>
                    {lang === "fr" ? "Native : " : "Native: "}{programme.currency}
                  </span>
                </>
              )}
              <LiveBadge on={progRealtime} lang={lang} />
            </div>
            <h1 className="page-title" style={{ marginBottom: 4 }}>
              ◇ {displayName}
            </h1>
            {programme.description && (
              <div className="page-sub" style={{ maxWidth: 760 }}>{programme.description}</div>
            )}
            {(programme.start_date || programme.end_date) && (
              <div className="text-faint mono" style={{ fontSize: 11.5, marginTop: 4 }}>
                {programme.start_date && <>{lang === "fr" ? "Début : " : "Start: "}{programme.start_date}</>}
                {programme.start_date && programme.end_date && <span style={{ margin: "0 6px" }}>·</span>}
                {programme.end_date && <>{lang === "fr" ? "Fin : " : "End: "}{programme.end_date}</>}
              </div>
            )}
          </div>
          <div className="pd-header-actions">
            <button className="btn sm" onClick={() => {
              const date = new Date().toISOString().slice(0, 10);
              const rows = attachedProjects.map((p) => ({
                code: p.id,
                name: projectName(p, lang),
                sector: sectorById(p.sector) ? sectorLabel(sectorById(p.sector), lang) : "",
                lead: p.lead || "",
                status: p.status || "",
                phase: p.phase || "",
                progress_pct: p.progress != null ? p.progress : "",
                risk: p.risk || "",
                native_currency: p.nativeCurrency || "EUR",
                budget_native: p.budget != null ? Number(p.budget).toFixed(2) : "",
                disbursed_native: p.disbursed != null ? Number(p.disbursed).toFixed(2) : "",
                sites: p.sites || 0,
                indicators: p.indic || 0,
              }));
              window.melr.exportCSV(`programme-${programme.code}-projets-${date}.csv`, rows, [
                { key: "code",             label: "Code" },
                { key: "name",             label: lang === "fr" ? "Nom" : "Name" },
                { key: "sector",           label: lang === "fr" ? "Secteur" : "Sector" },
                { key: "lead",             label: lang === "fr" ? "Responsable" : "Lead" },
                { key: "status",           label: lang === "fr" ? "Statut" : "Status" },
                { key: "phase",            label: "Phase" },
                { key: "progress_pct",     label: lang === "fr" ? "Avancement %" : "Progress %" },
                { key: "risk",             label: lang === "fr" ? "Risque" : "Risk" },
                { key: "native_currency",  label: lang === "fr" ? "Devise native" : "Native currency" },
                { key: "budget_native",    label: lang === "fr" ? "Budget natif (M)" : "Native budget (M)" },
                { key: "disbursed_native", label: lang === "fr" ? "Décaissé natif (M)" : "Native disbursed (M)" },
                { key: "sites",            label: "Sites" },
                { key: "indicators",       label: lang === "fr" ? "Indicateurs" : "Indicators" },
              ]);
            }}>
              <Icon.download /> {lang === "fr" ? "Exporter projets" : "Export projects"}
            </button>
            <button className="btn sm primary" onClick={() => setEditOpen(true)}>
              <Icon.edit /> {lang === "fr" ? "Modifier" : "Edit"}
            </button>
            <button className="btn sm" onClick={() => setDeleteConfirm(true)} style={{ color: "var(--red)" }}>
              <Icon.trash /> {lang === "fr" ? "Supprimer" : "Delete"}
            </button>
          </div>
        </div>

        <div className="pd-tabs">
          {TABS.map((tb) => (
            <button key={tb.k} className={"pd-tab" + (tab === tb.k ? " active" : "")} onClick={() => setTab(tb.k)}>
              {tb.l} {tb.c !== undefined && <span className="pd-tab-c">{tb.c}</span>}
            </button>
          ))}
        </div>
      </div>

      <div className="page-body">
        {/* KPI grid */}
        <div className="grid cols-4" style={{ marginBottom: 16 }}>
          <div className="kpi">
            <div className="kpi-label">{lang === "fr" ? "Projets rattachés" : "Attached projects"}</div>
            <div className="kpi-value">{attachedProjects.length}</div>
            <div className="kpi-sub">{sectorLabel(sector, lang)}</div>
          </div>
          <div className="kpi">
            <div className="kpi-label">{lang === "fr" ? "Budget cumulé" : "Cumulative budget"}</div>
            <div className="kpi-value">{fmtM(kpis.totalBudgetEur)}</div>
            <div className="kpi-sub">
              {fmtM(kpis.totalDisbEur)} {lang === "fr" ? "décaissés" : "disbursed"}
              {kpis.totalBudgetEur > 0 && (
                <> · {Math.round(kpis.totalDisbEur / kpis.totalBudgetEur * 100)}%</>
              )}
            </div>
          </div>
          <div className="kpi">
            <div className="kpi-label">{lang === "fr" ? "Avancement moyen" : "Average progress"}</div>
            <div className="kpi-value">{kpis.avgProgress}%</div>
            <div className="kpi-sub">{lang === "fr" ? "pondéré projets" : "project-weighted"}</div>
          </div>
          <div className="kpi">
            <div className="kpi-label">{lang === "fr" ? "Sites & indicateurs" : "Sites & indicators"}</div>
            <div className="kpi-value">{kpis.totalSites}</div>
            <div className="kpi-sub">{kpis.totalIndic} {lang === "fr" ? "indicateurs cumulés" : "indicators cumulated"}</div>
          </div>
        </div>

        {tab === "overview" && (
          <div className="grid" style={{ gridTemplateColumns: "1.6fr 1fr", gap: 16 }}>
            <div className="card">
              <div className="card-head">
                <div className="card-title">{lang === "fr" ? "Aperçu des projets" : "Projects overview"}</div>
              </div>
              <div className="card-body flush">
                {attachedProjects.length === 0 ? (
                  <div style={{ padding: 24, textAlign: "center" }}>
                    <div className="text-faint" style={{ fontSize: 13, marginBottom: 6 }}>
                      {lang === "fr" ? "Aucun projet rattaché à ce programme." : "No project attached to this programme yet."}
                    </div>
                    <div className="text-faint" style={{ fontSize: 11.5 }}>
                      {lang === "fr"
                        ? "Lors de la création d'un projet, sélectionnez ce programme dans le champ « Programme parent »."
                        : "When creating a project, pick this programme in the “Parent programme” field."}
                    </div>
                  </div>
                ) : (
                  <table className="tbl">
                    <thead><tr>
                      <th style={{ width: 70 }}>ID</th>
                      <th>{lang === "fr" ? "Projet" : "Project"}</th>
                      <th className="num">{lang === "fr" ? "Budget" : "Budget"}</th>
                      <th style={{ width: 140 }}>{lang === "fr" ? "Avancement" : "Progress"}</th>
                    </tr></thead>
                    <tbody>
                      {attachedProjects.slice(0, 8).map((p) => (
                        <tr key={p.id} className="row-link" onClick={() => onOpen && onOpen(p.id)}>
                          <td className="mono text-faint">{p.id}</td>
                          <td className="strong">{projectName(p, lang)}</td>
                          <td className="num mono">{fmtP(p.budget, p.nativeCurrency)}</td>
                          <td>
                            <div className="row gap-sm">
                              <div className="bar" style={{ width: 80 }}><div className="bar-fill" style={{ width: p.progress + "%" }}></div></div>
                              <span className="mono num-sm">{p.progress}%</span>
                            </div>
                          </td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                )}
              </div>
            </div>

            <div className="card">
              <div className="card-head">
                <div className="card-title">{lang === "fr" ? "Métadonnées" : "Metadata"}</div>
              </div>
              <div className="card-body" style={{ display: "grid", gap: 8, fontSize: 12 }}>
                <PRow label={lang === "fr" ? "Code" : "Code"} value={<span className="mono">{programme.code}</span>} />
                <PRow label={lang === "fr" ? "Nom FR" : "Name FR"} value={programme.name_fr} />
                <PRow label={lang === "fr" ? "Nom EN" : "Name EN"} value={programme.name_en || "—"} />
                <PRow label={lang === "fr" ? "Secteur" : "Sector"} value={sectorLabel(sector, lang)} />
                <PRow label={lang === "fr" ? "Début" : "Start"} value={programme.start_date || "—"} />
                <PRow label={lang === "fr" ? "Fin" : "End"} value={programme.end_date || "—"} />
                <PRow label={lang === "fr" ? "Budget natif" : "Native budget"}
                  value={programme.budget ? `${(programme.budget / 1_000_000).toFixed(2)}M ${programme.currency}` : "—"} />
                <PRow label={lang === "fr" ? "Créé le" : "Created on"} value={programme.created_at ? programme.created_at.slice(0, 10) : "—"} />
              </div>
            </div>
          </div>
        )}

        {tab === "projects" && (
          <div className="card">
            <div className="card-head">
              <div className="card-title">{lang === "fr" ? "Tous les projets rattachés" : "All attached projects"}</div>
              <span className="pill" style={{ marginLeft: 8 }}>{attachedProjects.length}</span>
            </div>
            <div className="card-body flush">
              {attachedProjects.length === 0 ? (
                <div className="text-faint" style={{ padding: 24, textAlign: "center" }}>
                  {lang === "fr" ? "Aucun projet rattaché." : "No project attached."}
                </div>
              ) : (
                <table className="tbl">
                  <thead><tr>
                    <th style={{ width: 70 }}>ID</th>
                    <th>{lang === "fr" ? "Projet" : "Project"}</th>
                    <th>{lang === "fr" ? "Secteur" : "Sector"}</th>
                    <th>{lang === "fr" ? "Responsable" : "Lead"}</th>
                    <th className="num">{lang === "fr" ? "Budget" : "Budget"}</th>
                    <th className="num">{lang === "fr" ? "Décaissé" : "Disbursed"}</th>
                    <th style={{ width: 140 }}>{lang === "fr" ? "Avancement" : "Progress"}</th>
                    <th>{lang === "fr" ? "Risque" : "Risk"}</th>
                  </tr></thead>
                  <tbody>
                    {attachedProjects.map((p) => {
                      const ps = sectorById(p.sector);
                      return (
                        <tr key={p.id} className="row-link" onClick={() => onOpen && onOpen(p.id)}>
                          <td className="mono text-faint">{p.id}</td>
                          <td className="strong">{projectName(p, lang)}</td>
                          <td><span className="sector-chip" style={{ background: ps.bg, color: ps.color, borderColor: ps.color }}>{sectorLabel(ps, lang)}</span></td>
                          <td>{p.lead}</td>
                          <td className="num mono">{fmtP(p.budget, p.nativeCurrency)}</td>
                          <td className="num mono">{fmtP(p.disbursed, p.nativeCurrency)}</td>
                          <td>
                            <div className="row gap-sm">
                              <div className="bar" style={{ width: 80 }}><div className="bar-fill" style={{ width: p.progress + "%" }}></div></div>
                              <span className="mono num-sm">{p.progress}%</span>
                            </div>
                          </td>
                          <td>
                            {p.risk === "ok"   && <span className="pill green dot">OK</span>}
                            {p.risk === "warn" && <span className="pill amber dot">{lang === "fr" ? "Vigilance" : "Watch"}</span>}
                            {p.risk === "bad"  && <span className="pill red dot">{lang === "fr" ? "Élevé" : "High"}</span>}
                          </td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              )}
            </div>
          </div>
        )}

        {tab === "indicators" && (
          <>
            {/* Summary KPIs for the rollup */}
            <div className="grid cols-4" style={{ marginBottom: 16 }}>
              <div className="kpi">
                <div className="kpi-label">{lang === "fr" ? "Indicateurs consolidés" : "Consolidated indicators"}</div>
                <div className="kpi-value">{indicatorStats.total}</div>
                <div className="kpi-sub">
                  {attachedProjects.length} {lang === "fr" ? "projets" : "projects"}
                </div>
              </div>
              <div className="kpi">
                <div className="kpi-label">{lang === "fr" ? "Sur cible" : "On target"}</div>
                <div className="kpi-value" style={{ color: "var(--green)" }}>{indicatorStats.onTarget}</div>
                <div className="kpi-sub">
                  {indicatorStats.total > 0
                    ? Math.round(indicatorStats.onTarget / indicatorStats.total * 100) + "%"
                    : "—"}
                </div>
              </div>
              <div className="kpi">
                <div className="kpi-label">{lang === "fr" ? "Sous cible / À risque" : "Below target / At risk"}</div>
                <div className="kpi-value" style={{ color: "var(--amber)" }}>
                  {indicatorStats.watch + indicatorStats.risk}
                </div>
                <div className="kpi-sub">
                  {indicatorStats.watch} {lang === "fr" ? "vigilance" : "watch"} · {indicatorStats.risk} {lang === "fr" ? "critique" : "critical"}
                </div>
              </div>
              <div className="kpi">
                <div className="kpi-label">{lang === "fr" ? "Avancement cible moyen" : "Avg progress to target"}</div>
                <div className="kpi-value">{indicatorStats.avgPct}%</div>
                <div className="kpi-sub">
                  {indicatorStats.pending} {lang === "fr" ? "sans données" : "no data"}
                </div>
              </div>
            </div>

            {/* Rollup table — grouped by level */}
            <div className="card">
              <div className="card-head">
                <div className="card-title">{lang === "fr" ? "Indicateurs des projets rattachés" : "Indicators of attached projects"}</div>
                <span className="text-faint" style={{ fontSize: 11.5, marginLeft: 8 }}>
                  {lang === "fr"
                    ? "Groupé par niveau · cliquer un projet pour ouvrir son détail"
                    : "Grouped by level · click a project code to open its detail"}
                </span>
                <div style={{ flex: 1 }}></div>
                <button className="btn xs" onClick={() => {
                  const date = new Date().toISOString().slice(0, 10);
                  window.melr.exportCSV(`programme-${programme.code}-indicateurs-${date}.csv`,
                    indicatorRollup.map((i) => ({
                      project_code: i.projectCode,
                      indicator_code: i.code,
                      level: i.level,
                      name: i.name,
                      unit: i.unit,
                      baseline: i.baseline,
                      target: i.target,
                      actual: i.actual,
                      progress_pct: i.pct,
                      status: i.status,
                    })),
                    [
                      { key: "project_code",   label: lang === "fr" ? "Projet"     : "Project" },
                      { key: "indicator_code", label: "Code" },
                      { key: "level",          label: lang === "fr" ? "Niveau"     : "Level" },
                      { key: "name",           label: lang === "fr" ? "Libellé"    : "Name" },
                      { key: "unit",           label: lang === "fr" ? "Unité"      : "Unit" },
                      { key: "baseline",       label: "Baseline" },
                      { key: "target",         label: lang === "fr" ? "Cible"      : "Target" },
                      { key: "actual",         label: lang === "fr" ? "Actuel"     : "Actual" },
                      { key: "progress_pct",   label: lang === "fr" ? "Progrès %"  : "Progress %" },
                      { key: "status",         label: lang === "fr" ? "Statut"     : "Status" },
                    ]);
                }}>
                  <Icon.download /> {lang === "fr" ? "Exporter" : "Export"}
                </button>
              </div>
              <div className="card-body flush">
                {lindLoading ? (
                  <div className="text-faint" style={{ padding: 24, textAlign: "center" }}>
                    {lang === "fr" ? "Chargement des indicateurs…" : "Loading indicators…"}
                  </div>
                ) : indicatorRollup.length === 0 ? (
                  <div style={{ padding: 24, textAlign: "center" }}>
                    <div className="text-faint" style={{ fontSize: 13, marginBottom: 6 }}>
                      {lang === "fr"
                        ? "Aucun indicateur défini sur les projets rattachés."
                        : "No indicator defined yet on the attached projects."}
                    </div>
                    <div className="text-faint" style={{ fontSize: 11.5 }}>
                      {lang === "fr"
                        ? "Ouvrez un projet (onglet Indicateurs) ou la page « Suivi des indicateurs » pour en créer."
                        : 'Open a project (Indicators tab) or the "Indicator tracking" page to create some.'}
                    </div>
                  </div>
                ) : (
                  <table className="tbl">
                    <thead><tr>
                      <th style={{ width: 60 }}>Code</th>
                      <th style={{ width: 70 }}>{lang === "fr" ? "Niveau" : "Level"}</th>
                      <th>{lang === "fr" ? "Libellé" : "Name"}</th>
                      <th style={{ width: 70 }}>{lang === "fr" ? "Projet" : "Project"}</th>
                      <th className="num" style={{ width: 70 }}>Baseline</th>
                      <th className="num" style={{ width: 70 }}>{lang === "fr" ? "Actuel" : "Current"}</th>
                      <th className="num" style={{ width: 70 }}>{lang === "fr" ? "Cible" : "Target"}</th>
                      <th style={{ width: 140 }}>{lang === "fr" ? "Progrès" : "Progress"}</th>
                      <th style={{ width: 90 }}>{lang === "fr" ? "Statut" : "Status"}</th>
                    </tr></thead>
                    <tbody>
                      {indicatorRollup.map((i) => {
                        const levelLabel = i.level === "outcome" ? (lang === "fr" ? "Effet"   : "Outcome")
                          : i.level === "output"  ? (lang === "fr" ? "Produit" : "Output")
                          : i.level === "impact"  ? (lang === "fr" ? "Impact"  : "Impact")
                          : i.level;
                        const levelClass = i.level === "outcome" ? "violet"
                          : i.level === "impact"  ? "amber"
                          : "";
                        return (
                          <tr key={i.uuid}>
                            <td className="mono text-faint">{i.code}</td>
                            <td>
                              <span className={"pill xs " + levelClass} style={{ fontSize: 9.5 }}>{levelLabel}</span>
                            </td>
                            <td className="strong">{i.name}</td>
                            <td>
                              <span className="tag-mono row-link"
                                onClick={() => onOpen && onOpen(i.projectCode)}
                                style={{ cursor: "pointer", fontSize: 10.5 }}
                                title={lang === "fr" ? "Ouvrir le projet" : "Open project"}>
                                {i.projectCode}
                              </span>
                            </td>
                            <td className="num mono muted">{i.baseline}{i.unit}</td>
                            <td className="num mono strong">{i.actual}{i.unit}</td>
                            <td className="num mono">{i.target}{i.unit}</td>
                            <td>
                              <div className="row gap-sm">
                                <div className="bar" style={{ width: 80 }}>
                                  <div className="bar-fill"
                                    style={{
                                      width: Math.min(100, i.pct) + "%",
                                      background: i.status === "ok" ? "var(--green)" : i.status === "warn" ? "var(--amber)" : i.status === "risk" ? "var(--red)" : "var(--text-faint)",
                                    }}>
                                  </div>
                                </div>
                                <span className="mono num-sm">{i.pct}%</span>
                              </div>
                            </td>
                            <td>
                              {i.status === "ok" && <span className="pill green dot">OK</span>}
                              {i.status === "warn" && <span className="pill amber dot">{lang === "fr" ? "Vigilance" : "Watch"}</span>}
                              {i.status === "risk" && <span className="pill red dot">{lang === "fr" ? "Critique" : "Critical"}</span>}
                              {i.status === "pending" && <span className="pill" style={{ background: "var(--bg-sunken)", color: "var(--text-faint)" }}>{lang === "fr" ? "En attente" : "Pending"}</span>}
                            </td>
                          </tr>
                        );
                      })}
                    </tbody>
                  </table>
                )}
              </div>
            </div>
          </>
        )}

        {tab === "gantt" && (
          <div className="card">
            <div className="card-head">
              <div className="card-title">{lang === "fr" ? "Gantt consolidé du programme" : "Consolidated programme Gantt"}</div>
              <span className="text-faint" style={{ fontSize: 11.5, marginLeft: 8 }}>
                {lang === "fr"
                  ? "Une ligne par projet, agrégée à partir des Gantt projets · cliquer pour ouvrir"
                  : "One row per project, aggregated from project Gantts · click to open"}
              </span>
            </div>
            {attachedProjects.length === 0 ? (
              <div className="text-faint" style={{ padding: 24, textAlign: "center" }}>
                {lang === "fr" ? "Aucun projet à afficher." : "No project to display."}
              </div>
            ) : (
              <ProgrammeGantt projects={attachedProjects} lang={lang} />
            )}
          </div>
        )}

        {tab === "activity" && (
          <div className="card">
            <div className="card-head">
              <div className="card-title">{lang === "fr" ? "Journal d'activité" : "Activity log"}</div>
              <span className="pill" style={{ marginLeft: 8 }}>{activityFeed.length}</span>
              <span className="text-faint" style={{ fontSize: 11.5, marginLeft: 8 }}>
                {lang === "fr"
                  ? "Évènements dérivés des dates de création/MAJ des entités (programme, projets, indicateurs, mesures)"
                  : "Events derived from creation/update timestamps (programme, projects, indicators, measurements)"}
              </span>
            </div>
            <div className="card-body flush">
              {activityFeed.length === 0 ? (
                <div className="text-faint" style={{ padding: 24, textAlign: "center", fontSize: 13 }}>
                  {lang === "fr"
                    ? "Aucune activité enregistrée pour ce programme."
                    : "No activity recorded for this programme."}
                </div>
              ) : (
                <div style={{ position: "relative", padding: "8px 0" }}>
                  {/* Vertical timeline line */}
                  <div style={{
                    position: "absolute", left: 26, top: 0, bottom: 0,
                    width: 2, background: "var(--line-faint)",
                  }} />
                  {activityFeed.map((evt, i) => {
                    let date;
                    try {
                      const d = new Date(evt.ts);
                      date = isNaN(d.getTime()) ? evt.ts : d.toLocaleDateString(lang === "fr" ? "fr-FR" : "en-US", { year: "numeric", month: "short", day: "numeric" });
                    } catch (e) { date = evt.ts; }
                    return (
                      <div key={i} style={{
                        display: "grid",
                        gridTemplateColumns: "56px 1fr",
                        padding: "10px 14px 10px 0",
                        alignItems: "start",
                        position: "relative",
                      }}>
                        <div style={{
                          width: 18, height: 18, borderRadius: "50%",
                          background: evt.color, color: "white",
                          display: "flex", alignItems: "center", justifyContent: "center",
                          fontSize: 11, fontWeight: 700,
                          marginLeft: 17, marginTop: 2,
                          flexShrink: 0,
                          position: "relative", zIndex: 1,
                        }}>{evt.icon}</div>
                        <div>
                          <div style={{ display: "flex", alignItems: "baseline", gap: 8 }}>
                            <span className="strong" style={{ fontSize: 12.5 }}>{evt.label}</span>
                            <span className="text-faint mono" style={{ fontSize: 10.5 }}>{date}</span>
                          </div>
                          <div className="text-faint" style={{ fontSize: 11.5, marginTop: 1 }}>
                            {evt.detail}
                          </div>
                        </div>
                      </div>
                    );
                  })}
                </div>
              )}
            </div>
            <div className="text-faint" style={{ fontSize: 10.5, padding: "8px 14px", borderTop: "1px solid var(--line-faint)" }}>
              {lang === "fr"
                ? "Note : ce journal est dérivé des champs created_at / updated_at des tables. Un audit trail par champ et utilisateur nécessite un dispositif d'audit dédié (triggers Postgres + table de journal)."
                : "Note: this log is derived from created_at / updated_at fields. A per-field, per-user audit trail would require dedicated audit infrastructure (Postgres triggers + log table)."}
            </div>
          </div>
        )}
      </div>

      {/* ========= Edit modal ========= */}
      {editOpen && (
        <EditProgrammeModal
          lang={lang}
          programme={programme}
          onClose={() => setEditOpen(false)}
          onSaved={async () => {
            await refreshProgrammes();
            setEditOpen(false);
          }}
        />
      )}

      {/* ========= Delete confirm ========= */}
      {deleteConfirm && (
        <div onClick={() => !busy && setDeleteConfirm(false)} style={{
          position: "fixed", inset: 0, background: "rgba(0,0,0,.45)", zIndex: 9999,
          display: "flex", alignItems: "center", justifyContent: "center",
        }}>
          <div onClick={(e) => e.stopPropagation()} style={{
            background: "var(--bg, white)", color: "var(--text, #111)",
            padding: 22, borderRadius: 10, width: 460, maxWidth: "92vw",
            boxShadow: "0 10px 30px rgba(0,0,0,.25)",
          }}>
            <div style={{ fontSize: 18, fontWeight: 600, marginBottom: 8 }}>
              {lang === "fr" ? "Supprimer le programme ?" : "Delete this programme?"}
            </div>
            <div className="text-muted" style={{ fontSize: 13, marginBottom: 14 }}>
              {lang === "fr"
                ? <>Cette action est <b>irréversible</b>. Les projets actuellement rattachés ne seront pas supprimés, mais leur lien vers ce programme sera retiré ({attachedProjects.length} projet{attachedProjects.length > 1 ? "s" : ""} concerné{attachedProjects.length > 1 ? "s" : ""}).</>
                : <>This action is <b>irreversible</b>. Currently attached projects will not be deleted, but their link to this programme will be cleared ({attachedProjects.length} affected).</>}
            </div>
            {err && <div style={{ color: "#b91c1c", fontSize: 12, marginBottom: 10 }}>{err}</div>}
            <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
              <button onClick={() => setDeleteConfirm(false)} disabled={busy}
                style={{ padding: "8px 14px", borderRadius: 6, border: "1px solid var(--line)", background: "transparent", cursor: "pointer" }}>
                {lang === "fr" ? "Annuler" : "Cancel"}
              </button>
              <button onClick={onDelete} disabled={busy}
                style={{ padding: "8px 14px", borderRadius: 6, border: 0, background: "#dc2626", color: "white", cursor: "pointer", fontWeight: 600 }}>
                {busy ? "…" : (lang === "fr" ? "Supprimer" : "Delete")}
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

function PRow({ label, value }) {
  return (
    <div style={{ display: "grid", gridTemplateColumns: "120px 1fr", gap: 8, padding: "4px 0", borderBottom: "1px solid var(--line-faint)" }}>
      <div className="text-faint">{label}</div>
      <div>{value}</div>
    </div>
  );
}

window.ProgrammeDetail = ProgrammeDetail;

// ==================== EDIT PROGRAMME MODAL ====================
function EditProgrammeModal({ lang, programme, onClose, onSaved }) {
  const [code, setCode]         = useStatePD2(programme.code || "");
  const [nameFr, setNameFr]     = useStatePD2(programme.name_fr || "");
  const [nameEn, setNameEn]     = useStatePD2(programme.name_en || "");
  const [sectorId, setSectorId] = useStatePD2(programme.sector_id || "sante");
  const [description, setDescription] = useStatePD2(programme.description || "");
  const [startDate, setStartDate] = useStatePD2(programme.start_date || "");
  const [endDate, setEndDate]     = useStatePD2(programme.end_date || "");
  const [budget, setBudget]     = useStatePD2(
    programme.budget != null ? String((programme.budget / 1_000_000).toFixed(2)) : ""
  );
  const [progCcy, setProgCcy]   = useStatePD2(programme.currency || "EUR");
  const [submitting, setSubmitting] = useStatePD2(false);
  const [err, setErr]           = useStatePD2(null);
  const rates = window.melr.getMergedRates();
  // Live sectors (DB-backed). Falls back to the legacy static SECTORS while
  // the first fetch is in flight; realtime keeps the list fresh.
  const { data: liveSectors } = window.melr.useSectors();
  const [newSectorOpen, setNewSectorOpen] = useStatePD2(false);
  const SECTOR_CHOICES = (liveSectors && liveSectors.length > 0)
    ? liveSectors
    : ((typeof SECTORS !== "undefined" && SECTORS) || []);

  const onSectorChange = (val) => {
    if (val === "__NEW__") setNewSectorOpen(true);
    else                   setSectorId(val);
  };

  const submit = async (e) => {
    e.preventDefault();
    setErr(null); setSubmitting(true);
    try {
      await window.melr.updateProgramme(programme.id, {
        code: code.trim(),
        name_fr: nameFr.trim(),
        name_en: nameEn.trim() || nameFr.trim(),
        sector_id: sectorId,
        description: description.trim() || null,
        start_date: startDate || null,
        end_date:   endDate   || null,
        budget_native: budget,
        currency: progCcy,
      });
      if (onSaved) await onSaved();
    } catch (e2) {
      setErr(e2.message);
    } finally {
      setSubmitting(false);
    }
  };

  const inp = { padding: "8px 10px", borderRadius: 6, border: "1px solid var(--line)", fontSize: 13 };
  const lbl = { fontSize: 11, opacity: 0.75 };

  return (
    <Modal
      title={lang === "fr" ? "Modifier le programme" : "Edit programme"}
      onClose={onClose}
      onSubmit={submit}
      footer={<>
        <button type="button" className="btn sm ghost" onClick={onClose} disabled={submitting}>
          {lang === "fr" ? "Annuler" : "Cancel"}
        </button>
        <button type="submit" disabled={submitting}
          style={{ padding: "8px 14px", borderRadius: 6, border: 0, background: "#059669", color: "white", cursor: "pointer", fontWeight: 600 }}>
          {submitting ? "…" : (lang === "fr" ? "Enregistrer" : "Save")}
        </button>
      </>}>
      <div style={{ display: "grid", gap: 10 }}>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 2fr", gap: 10 }}>
          <label style={{ display: "grid", gap: 4 }}>
            <span style={lbl}>{lang === "fr" ? "Code" : "Code"}</span>
            <input required value={code} onChange={(e) => setCode(e.target.value)} style={inp} />
          </label>
          <label style={{ display: "grid", gap: 4 }}>
            <span style={lbl}>{lang === "fr" ? "Nom FR" : "Name FR"}</span>
            <input required value={nameFr} onChange={(e) => setNameFr(e.target.value)} style={inp} />
          </label>
        </div>
        <label style={{ display: "grid", gap: 4 }}>
          <span style={lbl}>{lang === "fr" ? "Nom EN (optionnel)" : "Name EN (optional)"}</span>
          <input value={nameEn} onChange={(e) => setNameEn(e.target.value)} style={inp} />
        </label>
        <label style={{ display: "grid", gap: 4 }}>
          <span style={lbl}>{lang === "fr" ? "Secteur" : "Sector"}</span>
          <select value={sectorId} onChange={(e) => onSectorChange(e.target.value)} style={inp}>
            {SECTOR_CHOICES.map((s) => (
              <option key={s.id} value={s.id}>{lang === "en" ? s.en : s.fr}</option>
            ))}
            <option value="__NEW__">{lang === "fr" ? "+ Nouveau secteur…" : "+ New sector…"}</option>
          </select>
        </label>
        <label style={{ display: "grid", gap: 4 }}>
          <span style={lbl}>{lang === "fr" ? "Description" : "Description"}</span>
          <textarea value={description} onChange={(e) => setDescription(e.target.value)} rows={2}
            style={{ ...inp, resize: "vertical" }} />
        </label>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
          <label style={{ display: "grid", gap: 4 }}>
            <span style={lbl}>{lang === "fr" ? "Date début" : "Start date"}</span>
            <input type="date" value={startDate} onChange={(e) => setStartDate(e.target.value)} style={inp} />
          </label>
          <label style={{ display: "grid", gap: 4 }}>
            <span style={lbl}>{lang === "fr" ? "Date fin" : "End date"}</span>
            <input type="date" value={endDate} onChange={(e) => setEndDate(e.target.value)} style={inp} />
          </label>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "2fr 1fr", gap: 10 }}>
          <label style={{ display: "grid", gap: 4 }}>
            <span style={lbl}>{lang === "fr" ? "Budget (en millions)" : "Budget (in millions)"}</span>
            <input type="number" step="0.1" value={budget} onChange={(e) => setBudget(e.target.value)} style={inp} />
          </label>
          <label style={{ display: "grid", gap: 4 }}>
            <span style={lbl}>{lang === "fr" ? "Devise native" : "Native currency"}</span>
            <select value={progCcy} onChange={(e) => setProgCcy(e.target.value)} style={inp}>
              {Object.keys(rates).map((c) => <option key={c} value={c}>{c}</option>)}
            </select>
          </label>
        </div>
        {err && <div style={{ color: "#b91c1c", fontSize: 12 }}>{err}</div>}
      </div>
      {newSectorOpen && (
        <NewSectorModal lang={lang}
          onClose={() => setNewSectorOpen(false)}
          onCreated={(sec) => { setSectorId(sec.id); setNewSectorOpen(false); }} />
      )}
    </Modal>
  );
}

window.EditProgrammeModal = EditProgrammeModal;
