/* =============================================================
   page-map.jsx — Full-width global map with country search
   Layout: [Search bar] → [Big map] → [Country drilldown below]
   ============================================================= */
const MAP_MODULE_AUDIT_ALIAS = "World Map";

function PageMap({ model, onOpenSite, onOpenInPM, role }) {
  // T025 — engineer/po/admin can navigate from a site card straight to the PM
  // editor with the canonical site identity preserved. Management stays
  // monitoring-only (no PM access by role gate), so the button hides for them.
  const canOpenInPM = !!onOpenInPM && (role === "engineer" || role === "po" || role === "admin");
  const [metric, setMetric] = React.useState("links");
  const [selected, setSelected] = React.useState(null);
  const [searchTerm, setSearchTerm] = React.useState("");
  const [showSuggest, setShowSuggest] = React.useState(false);
  const searchRef = React.useRef(null);

  // ---------- Per-country aggregate (FULL dataset, not filtered) ----------
  // PROP-11: enrich each country aggregate row with lifecycle data so the map
  // can colour by lifecycle phase or completion %.
  const countryData = React.useMemo(() => {
    const base = PRData.countryAggregate(model);
    if (!PRData.countryLifecycleAggregate) return base;
    const lifecycle = PRData.countryLifecycleAggregate(model);
    const byCountry = new Map();
    for (const l of lifecycle) byCountry.set((l.country || "").toLowerCase(), l);
    return base.map((row) => {
      const canon = window.COUNTRY_ISO ? window.COUNTRY_ISO.canonical(row.key) : row.key;
      const lc = byCountry.get((canon || "").toLowerCase()) || byCountry.get((row.key || "").toLowerCase()) || null;
      return {
        ...row,
        lifecycle: lc || null,
        sitesComplete: lc ? lc.sitesComplete : 0,
        blockedSites: lc ? lc.blockedSites : 0,
        averageLifecyclePercent: lc ? lc.averageLifecyclePercent : 0,
        dominantLifecyclePhase: lc ? lc.dominantLifecyclePhase : "no-data",
        dominantLifecyclePhaseLabel: lc ? lc.dominantLifecyclePhaseLabel : "No project data",
        readinessPercent: lc ? lc.readinessPercent : 0,
        blockedReadinessCount: lc ? lc.blockedReadinessCount : 0,
        sitesReadyForMigration: lc ? lc.sitesReadyForMigration : 0,
        readinessTrackedSites: lc ? lc.readinessTrackedSites : 0,
        linksInMigration: lc ? lc.linksInMigration : 0,
        postMigrationCompleteLinks: lc ? lc.postMigrationCompleteLinks : 0,
        readinessTrackedLinks: lc ? lc.readinessTrackedLinks : 0,
      };
    });
  }, [model]);

  // ---------- Drilldown for the selected country ----------
  const selectedData = React.useMemo(() => {
    return PRData.countryDrilldown(model, selected);
  }, [model, selected]);

  const canonical = selected ? window.COUNTRY_ISO.canonical(selected) : null;

  // ---------- Search suggestions ----------
  // Build a list of canonical country names with data, deduped.
  const allCountries = React.useMemo(() => {
    const m = new Map();
    for (const c of countryData) {
      const iso = window.COUNTRY_ISO.toISO(c.key);
      if (!iso) continue;
      const canon = window.COUNTRY_ISO.canonical(c.key);
      if (!m.has(canon)) m.set(canon, { canon, iso, key: c.key, sites: 0, links: 0 });
      const e = m.get(canon);
      e.sites += c.sites.size;
      e.links += c.links;
    }
    return [...m.values()].sort((a, b) => a.canon.localeCompare(b.canon));
  }, [countryData]);

  // T023: when actively searching, never silently truncate matches — a country
  // with valid workbook data must be reachable through search. Cap only the
  // empty-query default to keep the dropdown short on first focus.
  const SUGGEST_EMPTY_DEFAULT = 8;
  const suggestions = React.useMemo(() => {
    const q = searchTerm.trim().toLowerCase();
    if (!q) return allCountries.slice(0, SUGGEST_EMPTY_DEFAULT);
    return allCountries.filter((c) => c.canon.toLowerCase().includes(q));
  }, [searchTerm, allCountries]);
  const totalMatches = React.useMemo(() => {
    const q = searchTerm.trim().toLowerCase();
    if (!q) return allCountries.length;
    return allCountries.filter((c) => c.canon.toLowerCase().includes(q)).length;
  }, [searchTerm, allCountries]);

  function pickCountry(key) {
    setSelected(key);
    setSearchTerm("");
    setShowSuggest(false);
    // Smooth-scroll to drilldown
    setTimeout(() => {
      const el = document.getElementById("country-drilldown");
      if (el) {
        const rect = el.getBoundingClientRect();
        const offset = window.scrollY + rect.top - 80;
        window.scrollTo({ top: offset, behavior: "smooth" });
      }
    }, 50);
  }

  // Close suggestion dropdown when clicking outside
  React.useEffect(() => {
    function onDoc(e) {
      if (searchRef.current && !searchRef.current.contains(e.target)) {
        setShowSuggest(false);
      }
    }
    document.addEventListener("mousedown", onDoc);
    return () => document.removeEventListener("mousedown", onDoc);
  }, []);

  return (
    <div className="page">
      <PageHeader
        title="PR Global Entity"
        subtitle="Search a country or click any highlighted country to drill in. Map totals follow the project tracker inventory, including local project updates."
        right={
          <div className="flex gap-sm">
            <FilterSelect label="Color by" value={metric} onChange={setMetric} options={[
              { value: "links", label: "Canonical links" },
              { value: "atRisk", label: "At-risk links" },
              { value: "activated", label: "Activated links" },
              { value: "lifecycle", label: "Lifecycle %" },
              { value: "readiness", label: "Readiness %" },
              { value: "phase", label: "Dominant phase" },
            ]}/>
          </div>
        }
      />

      <div className="map-source-strip">
        <span><strong>Metric source</strong> Project tracker</span>
        <span>Canonical sites <strong className="mono">{(model.canonicalSites || model.sites || []).length}</strong></span>
        <span>Canonical links <strong className="mono">{(model.canonicalLinks || []).length}</strong></span>
        <span>Local project updates <strong className="mono">{model.overridesApplied || 0}</strong></span>
        <span>New Underlay readiness feeds country lifecycle</span>
        <span>Program baseline is not used for map totals</span>
      </div>

      {/* Country search */}
      <div ref={searchRef} className="map-search-wrap" style={{position: "relative", marginBottom: 14, maxWidth: 520}}>
        <div className="search-input map-search-input" style={{maxWidth: "none", padding: "8px 12px"}}>
          <Glyph name="search" size={15}/>
          <input
            className="map-search-field"
            value={searchTerm}
            onChange={(e) => { setSearchTerm(e.target.value); setShowSuggest(true); }}
            onFocus={() => setShowSuggest(true)}
            placeholder="Search country — try India, France, Japan, Argentina…"
            onKeyDown={(e) => {
              if (e.key === "Enter" && suggestions.length) pickCountry(suggestions[0].key);
              if (e.key === "Escape") { setShowSuggest(false); setSearchTerm(""); }
            }}
            style={{fontSize: 14}}
          />
          {(selected || searchTerm) && (
            <button className="btn ghost map-search-clear" style={{padding: "2px 6px", fontSize: 11}}
                    onClick={() => { setSelected(null); setSearchTerm(""); setShowSuggest(false); }}>
              {selected ? "Clear selection" : "Clear"}
            </button>
          )}
        </div>
        {showSuggest && suggestions.length > 0 && (
          <div className="map-search-suggest" data-total-matches={totalMatches} data-shown-matches={suggestions.length} style={{
            position: "absolute", top: "100%", left: 0, right: 0,
            marginTop: 4,
            background: "var(--surface)",
            border: "1px solid var(--line)",
            borderRadius: 10,
            boxShadow: "var(--shadow-2)",
            overflow: "hidden",
            zIndex: 20,
            maxHeight: 320,
            overflowY: "auto",
          }}>
            {suggestions.map((s) => (
              <button key={s.canon} className="map-search-suggest-item" data-country={s.canon} onClick={() => pickCountry(s.key)}
                style={{
                  width: "100%", textAlign: "left",
                  padding: "9px 12px",
                  background: "transparent", border: 0,
                  borderBottom: "1px solid var(--line-soft)",
                  fontSize: 13, cursor: "pointer",
                  display: "flex", justifyContent: "space-between", alignItems: "center",
                }}
                onMouseEnter={(e) => e.currentTarget.style.background = "var(--bg-elev)"}
                onMouseLeave={(e) => e.currentTarget.style.background = "transparent"}>
                <span style={{color: "var(--ink-900)", fontWeight: 500}}>{s.canon}</span>
                <span style={{fontSize: 11, color: "var(--ink-500)"}}>
                  <span className="mono">{s.sites}</span> sites · <span className="mono">{s.links}</span> canonical links
                </span>
              </button>
            ))}
            {searchTerm.trim() && (
              <div className="map-search-suggest-footer" style={{
                padding: "6px 12px", fontSize: 11, color: "var(--ink-500)",
                background: "var(--bg-elev)", borderTop: "1px solid var(--line-soft)",
              }}>
                Showing {suggestions.length} of {totalMatches} match{totalMatches === 1 ? "" : "es"}
              </div>
            )}
          </div>
        )}
      </div>

      {/* Full-width map */}
      <div style={{marginBottom: 14}}>
        <WorldMap
          countryData={countryData}
          metric={metric}
          selectedCountry={selected}
          onCountryClick={({ canonical, names }) => pickCountry(names[0])}
          height={Math.max(640, Math.round(window.innerHeight * 0.75))}
        />
      </div>

      {/* Country drilldown (below the map) */}
      <div id="country-drilldown" data-country-selected={canonical || ""}>
        {!selected || !selectedData ? (
          <div className="card map-drilldown-empty" style={{padding: 30}}>
            <div className="map-drilldown-empty-grid">
              <div>
                <div style={{fontSize: 11, color: "var(--ink-500)", textTransform: "uppercase", letterSpacing: "0.08em"}}>No country selected</div>
                <div style={{fontFamily: "var(--font-display)", fontSize: 22, fontWeight: 600, letterSpacing: "-0.02em", marginTop: 4}}>
                  Pick a country to drill in
                </div>
                <div style={{color: "var(--ink-500)", fontSize: 13.5, marginTop: 8, lineHeight: 1.5}}>
                  Use the search above, or click any highlighted country on the map. The drilldown shows every site, the vendor mix, criticality breakdown, and a dedicated discussion thread.
                </div>
              </div>
              <div>
                <div style={{fontSize: 11, color: "var(--ink-500)", textTransform: "uppercase", letterSpacing: "0.06em", marginBottom: 8}}>Top countries by canonical links</div>
                <BarChart data={countryData
                  .filter((c) => c.links > 0)
                  .sort((a, b) => b.links - a.links)
                  .slice(0, 6)
                  .map((c) => ({ label: window.COUNTRY_ISO.canonical(c.key), value: c.links, color: c.atRisk > 0 ? "var(--warn)" : "var(--accent)" }))} />
              </div>
            </div>
          </div>
        ) : (
          <div className="card map-drilldown-card" style={{padding: 0, overflow: "hidden"}}>
            {/* Header */}
            <div style={{padding: "18px 22px", borderBottom: "1px solid var(--line-soft)", background: "var(--bg-elev)", display: "flex", justifyContent: "space-between", alignItems: "center"}}>
              <div>
                <div style={{fontSize: 11, color: "var(--ink-500)", textTransform: "uppercase", letterSpacing: "0.08em"}}>Country drilldown</div>
                <div className="map-drilldown-title" style={{fontFamily: "var(--font-display)", fontSize: 26, fontWeight: 600, letterSpacing: "-0.02em", marginTop: 2}}>
                  {canonical}
                </div>
              </div>
              <button className="btn ghost" onClick={() => setSelected(null)}>
                <Glyph name="close" size={12}/> Close
              </button>
            </div>

            {/* Stats strip */}
            <div style={{padding: "16px 22px", display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(110px, 1fr))", gap: 10, borderBottom: "1px solid var(--line-soft)"}}>
              <Stat label="Canonical sites" value={selectedData.sites}/>
              <Stat label="Canonical links" value={selectedData.links}/>
              <Stat label="Ordered links" value={selectedData.ordered}/>
              <Stat label="Activated" value={selectedData.activated} tone="ok"/>
              <Stat label="HW delivered" value={selectedData.hwDelivered}/>
              <Stat label="Migrated" value={selectedData.migrated} tone="ok"/>
              <Stat label="At risk" value={selectedData.atRisk} tone={selectedData.atRisk ? "risk" : "muted"}/>
              <Stat label="Blocked" value={selectedData.blocked} tone={selectedData.blocked ? "warn" : "muted"}/>
              {(() => {
                const lc = countryData.find((c) => (window.COUNTRY_ISO.canonical(c.key) || c.key) === canonical);
                if (!lc || !lc.lifecycle) return null;
                return (
                  <>
                    <Stat label="Sites complete" value={lc.sitesComplete} tone={lc.sitesComplete ? "ok" : "muted"}/>
                    <Stat label="Avg lifecycle %" value={lc.averageLifecyclePercent + "%"} tone="ok"/>
                    <Stat label="Readiness %" value={lc.readinessPercent + "%"} tone={lc.readinessPercent >= 75 ? "ok" : "warn"}/>
                    <Stat label="Ready sites" value={`${lc.sitesReadyForMigration}/${lc.readinessTrackedSites}`} tone={lc.sitesReadyForMigration ? "ok" : "muted"}/>
                    <Stat label="Readiness blocked" value={lc.blockedReadinessCount} tone={lc.blockedReadinessCount ? "risk" : "muted"}/>
                  </>
                );
              })()}
            </div>

            {/* Body: 3 columns: Vendors + Criticality, Sites, Discussion */}
            <div className="map-drilldown-body">
              <div>
                <div style={{fontSize: 11, color: "var(--ink-500)", textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 8}}>Vendors</div>
                {selectedData.vendors.length === 0 ? (
                  <div className="muted" style={{fontSize: 12, marginBottom: 14}}>No vendor data.</div>
                ) : (
                  <div style={{display: "flex", gap: 6, flexWrap: "wrap", marginBottom: 14}}>
                    {selectedData.vendors.map(([v, n]) => (
                      <Pill key={v} kind="info">{v} <span className="mono" style={{marginLeft: 4, opacity: .7}}>{n}</span></Pill>
                    ))}
                  </div>
                )}

                <div style={{fontSize: 11, color: "var(--ink-500)", textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 8}}>Criticality mix</div>
                <div style={{display: "flex", gap: 6, flexWrap: "wrap"}}>
                  {selectedData.criticalities.length === 0 ? (
                    <span className="muted" style={{fontSize: 12}}>—</span>
                  ) : selectedData.criticalities.map(([c, n]) => (
                    <span key={c} style={{display:"flex", alignItems:"center", gap: 6}}>
                      <CriticalityPill value={c}/> <span className="mono" style={{fontSize: 11, color: "var(--ink-500)"}}>{n}</span>
                    </span>
                  ))}
                </div>
              </div>

              <div>
                <div style={{fontSize: 11, color: "var(--ink-500)", textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 8}}>
                  Sites in {canonical} ({selectedData.sitesInCountry.length})
                </div>
                <div style={{display: "flex", flexDirection: "column", gap: 4, maxHeight: 340, overflow: "auto", paddingRight: 6}}>
                  {selectedData.sitesInCountry.length === 0 && <span className="muted" style={{fontSize: 12}}>No sites recorded.</span>}
                  {selectedData.sitesInCountry.map((s) => {
                    const linkRefs = (s.canonicalLinkRefs || s.linkRefs || (s.links || []).map((l) => l && l.linkRef).filter(Boolean) || []);
                    const linkCount = (s.canonicalLinkRefs || s.linkRefs || s.links || []).length;
                    // PM payload contract: prefer the canonical siteCode, but fall
                    // back to siteName before shortLabel because the workbook can
                    // carry stub shortLabels like "0" while the site clearly has a
                    // human-readable name. page-pm.jsx::PageProjectManagement
                    // resolves overlay→sites via siteCode === idRef OR
                    // siteName.toLowerCase() === idLow, so siteName is the safe
                    // fallback when siteCode is missing.
                    const pmIdRef = s.siteCode || s.siteName || s.shortLabel;
                    return (
                    <div key={s.id} role="button" tabIndex={0}
                      className="map-drilldown-site-row"
                      data-site-code={s.siteCode || ""}
                      data-site-name={s.siteName || ""}
                      data-first-link-ref={linkRefs[0] || ""}
                      onClick={() => onOpenSite({ site: s })}
                      onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); onOpenSite({ site: s }); } }}
                      style={{
                        textAlign: "left", padding: "8px 10px", borderRadius: 8,
                        border: "1px solid var(--line-soft)", background: "var(--surface)",
                        display: "flex", justifyContent: "space-between", alignItems: "center",
                        cursor: "pointer", fontSize: 12.5,
                      }}>
                      <span style={{minWidth: 0, flex: 1}}>
                        <span style={{fontWeight: 500}}>{s.siteName || s.id}</span>
                        <span className="muted" style={{marginLeft: 8, fontFamily: "var(--font-mono)", fontSize: 11}}>{s.siteCode || "—"}</span>
                      </span>
                      <span style={{display: "flex", gap: 4, alignItems: "center", flexShrink: 0}}>
                        <CriticalityPill value={s.criticality} />
                        <span className="mono muted" style={{fontSize: 11}}>{linkCount}L</span>
                        {canOpenInPM && pmIdRef && (
                          <button
                            className="btn ghost map-drilldown-open-in-pm"
                            data-pm-entity="overlay"
                            data-pm-idref={pmIdRef}
                            style={{padding: "2px 6px", fontSize: 10.5}}
                            onClick={(e) => { e.stopPropagation(); onOpenInPM("overlay", pmIdRef); }}
                            title="Open this site in Project Management"
                          >
                            Open in PM
                          </button>
                        )}
                        <Glyph name="chevron" size={11}/>
                      </span>
                    </div>
                    );
                  })}
                </div>
              </div>

              <div>
                <div style={{fontSize: 11, color: "var(--ink-500)", textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 8}}>
                  Discussion · {canonical}
                </div>
                <div style={{height: 340, border: "1px solid var(--line-soft)", borderRadius: 10, overflow: "hidden"}}>
                  <ChatThread scopeKind="country" scopeId={canonical} title={canonical}/>
                </div>
              </div>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

function Stat({ label, value, tone }) {
  return (
    <div style={{
      padding: "10px 12px",
      borderRadius: 10,
      background: "var(--bg-elev)",
      border: "1px solid var(--line-soft)",
    }}>
      <div style={{fontSize: 10.5, textTransform: "uppercase", letterSpacing: "0.08em", color: "var(--ink-500)"}}>{label}</div>
      <div style={{
        fontFamily: "var(--font-display)",
        fontSize: 22, fontWeight: 600, letterSpacing: "-0.02em",
        color: tone === "ok" ? "var(--ok)" :
               tone === "risk" ? "var(--risk)" :
               tone === "warn" ? "var(--warn)" : "var(--ink-900)",
      }}>{value}</div>
    </div>
  );
}

window.PageMap = PageMap;
