/* Hunian Kita — role-aware, responsive Management Portal shell
   Roles: admin (Administrator) · pengelola (Estate Manager) · penghuni (Resident) */

const ROLE = (() => {
  // utamakan role ASLI dari backend (disimpan pas login), baru fallback ke ?role= di URL
  let r = null;
  try { r = (JSON.parse(localStorage.getItem("user") || "null") || {}).role; } catch (e) { /* abaikan */ }
  if (!["admin", "pengelola", "penghuni"].includes(r)) {
    r = new URLSearchParams(location.search).get("role");
  }
  return ["admin", "pengelola", "penghuni"].includes(r) ? r : "pengelola";
})();

const IDENTITY = {
  admin:     { name: "Dhany Indraswara", role: "Administrator", logout: "index.html" },
  pengelola: { name: "Rani Wibowo",      role: "Estate Manager", logout: "index.html" },
  penghuni:  { name: "Indah Permatasari", role: "Penghuni · C-12", logout: "index.html" },
};

const NAV_BY_ROLE = {
  admin: [
    { sec: "Platform", items: [
      { key: "platform",  label: "Portfolio",    icon: "layout-grid" },
      { key: "estates",   label: "Estates",      icon: "building-2" },
      { key: "operators", label: "Operators",    icon: "user-cog" },
      { key: "audit",     label: "Audit log",    icon: "scroll-text" },
    ]},
    { sec: "Operations", items: [
      { key: "dashboard", label: "Command center", icon: "layout-dashboard" },
      { key: "complaints", label: "Complaints", icon: "message-square-warning", badge: "open" },
      { key: "packages",  label: "Packages", icon: "package", badge: "pkg" },
      { key: "cctv",      label: "CCTV komplek", icon: "cctv" },
    ]},
    { sec: "Finance", items: [
      { key: "finance",   label: "IPL & finance", icon: "wallet" },
      { key: "contributions", label: "Iuran warga", icon: "hand-coins" },
      { key: "adspace",   label: "Sewa space iklan", icon: "megaphone" },
    ]},
  ],
  pengelola: [
    { sec: "Operations", items: [
      { key: "dashboard", label: "Command center", icon: "layout-dashboard" },
      { key: "complaints", label: "Complaints", icon: "message-square-warning", badge: "open" },
      { key: "packages",  label: "Packages", icon: "package", badge: "pkg" },
      { key: "visitors",  label: "Visitors", icon: "user-check", badge: "vis" },
      { key: "facilities", label: "Facilities", icon: "calendar-check", badge: "fac" },
    ]},
    { sec: "Community", items: [
      { key: "announcements", label: "Broadcast", icon: "megaphone" },
      { key: "letters", label: "Surat & izin", icon: "file-text", badge: "letters" },
      { key: "cctv", label: "CCTV komplek", icon: "cctv" },
      { key: "residents", label: "Residents", icon: "users" },
    ]},
    { sec: "Finance", items: [
      { key: "finance", label: "IPL & finance", icon: "wallet" },
      { key: "contributions", label: "Iuran warga", icon: "hand-coins" },
      { key: "adspace", label: "Sewa space iklan", icon: "megaphone" },
    ]},
  ],
  penghuni: [
    { sec: "Menu", items: [
      { key: "home",     label: "Beranda",          icon: "house" },
      { key: "bills",    label: "Tagihan & iuran",  icon: "wallet", badge: "bill" },
      { key: "report",   label: "Lapor & keluhan",  icon: "message-square-warning" },
      { key: "packages", label: "Paket saya",       icon: "package", badge: "mypkg" },
      { key: "letters",  label: "Surat & izin",     icon: "file-text" },
    ]},
    { sec: "Lainnya", items: [
      { key: "cctv",     label: "CCTV komplek",     icon: "cctv" },
      { key: "info",     label: "Informasi warga",  icon: "megaphone" },
      { key: "facilities", label: "Booking fasilitas", icon: "calendar-check" },
      { key: "adspace",  label: "Sewa space iklan", icon: "store" },
    ]},
  ],
};

const BOTTOM = [
  { key: "home",     label: "Beranda", icon: "house" },
  { key: "bills",    label: "Tagihan", icon: "wallet", badge: "bill" },
  { key: "report",   label: "Lapor",   icon: "message-square-warning" },
  { key: "packages", label: "Paket",   icon: "package", badge: "mypkg" },
  { key: "more",     label: "Lainnya", icon: "menu" },
];

const DEFAULT_ROUTE = { admin: "platform", pengelola: "dashboard", penghuni: "home" };

const TITLES = {
  dashboard: ["Command center", "Graha Asri Residence · live operations"],
  complaints: ["Complaints & work-orders", "Report, route, and resolve against SLA"],
  finance: ["IPL billing & collection", "Monthly dues, receivables, and reminders"],
  announcements: ["Broadcast center", "Reach every resident across channels"],
  facilities: ["Facility bookings", "Approve and schedule shared spaces"],
  visitors: ["Visitor management", "Live gate log and guest approvals"],
  residents: ["Resident directory", "Units, households, and contacts"],
  settings: ["Settings", "Profile, estate, billing, team, and security"],
  packages: ["Package room", "Parcels held at the guard post"],
  contributions: ["Iuran warga", "Patungan & urunan komunitas"],
  letters: ["Surat & izin", "Pengajuan surat pengantar, rujukan, dan izin"],
  cctv: ["CCTV komplek", "Pantauan kamera keamanan lingkungan"],
  adspace: ["Sewa space iklan", "Banner & spanduk — pemasukan kas RT"],
  platform: ["Platform overview", "All estates · live portfolio"],
  estates: ["Estates", "Communities under management"],
  operators: ["Operators", "Pengelola accounts and access"],
  audit: ["Audit log", "Every action across the platform"],
};
const TITLES_RES = {
  home: ["Beranda", "Graha Asri Residence · Unit C-12"],
  bills: ["Tagihan & iuran", "IPL, jimpitan, dan patungan warga — unit C-12"],
  report: ["Lapor & keluhan", "Sampaikan keluhan, pantau perbaikannya"],
  packages: ["Paket saya", "Paket yang dititip di pos satpam"],
  info: ["Informasi warga", "Pengumuman & kabar lingkungan"],
  facilities: ["Booking fasilitas", "Pesan fasilitas bersama"],
  letters: ["Surat & izin", "Ajukan surat RT & izin renovasi"],
  cctv: ["CCTV komplek", "Pantau kamera area umum komplek"],
  adspace: ["Sewa space iklan", "Pasang spanduk usaha di komplek"],
  settings: ["Pengaturan", "Profil & preferensi akun"],
};
function titleFor(role, route) {
  if (role === "penghuni" && TITLES_RES[route]) return TITLES_RES[route];
  return TITLES[route] || ["", ""];
}

function viewFor(role, route) {
  if (role === "penghuni") {
    return { home: ResHome, bills: ResBills, report: ResReport, packages: ResPackages,
      info: ResInfo, facilities: ResFacilities, settings: Settings,
      letters: Letters, cctv: CCTV, adspace: AdSpace }[route];
  }
  return { dashboard: Dashboard, complaints: Complaints, finance: Finance, announcements: Announcements,
    facilities: Facilities, visitors: Visitors, residents: Residents, settings: Settings,
    packages: Packages, contributions: Dues, platform: PlatformOverview, estates: Estates, operators: Operators, audit: AuditLog,
    letters: Letters, cctv: CCTV, adspace: AdSpace }[route];
}

const ACCENTS = {
  Cyan:    { p: "#02A0C1", s: "#3581E1" },
  Blue:    { p: "#3581E1", s: "#5B6CF0" },
  Teal:    { p: "#0E9F6E", s: "#0E7C86" },
  Violet:  { p: "#7A6CF0", s: "#5B6CF0" },
  Sunset:  { p: "#E0762A", s: "#DC4A3D" },
};

function softRgba(hex, a) {
  const h = hex.replace("#", "");
  const r = parseInt(h.slice(0, 2), 16), g = parseInt(h.slice(2, 4), 16), b = parseInt(h.slice(4, 6), 16);
  return `rgba(${r}, ${g}, ${b}, ${a})`;
}

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "Cyan",
  "dark": false,
  "density": "regular"
}/*EDITMODE-END*/;

/* sidebar context card per role */
function EstateCard({ role }) {
  const HK = window.HK;
  if (role === "admin") {
    return (
      <div className="estate">
        <span className="av" style={{ background: "linear-gradient(135deg,#02A0C1,#7A6CF0)" }}><Icon name="layers" size={16} /></span>
        <div style={{ flex: 1, minWidth: 0 }}><div className="en">All estates</div><div className="em">{HK.platform.estates} estates · {HK.platform.units.toLocaleString("id-ID")} units</div></div>
        <Icon name="chevrons-up-down" size={16} className="chev" />
      </div>
    );
  }
  if (role === "penghuni") {
    return (
      <div className="estate">
        <span className="av">{HK.me.unit.split("-")[0]}</span>
        <div style={{ flex: 1, minWidth: 0 }}><div className="en">Unit {HK.me.unit}</div><div className="em">{HK.me.name} · Graha Asri</div></div>
        <Icon name="chevrons-up-down" size={16} className="chev" />
      </div>
    );
  }
  return (
    <div className="estate">
      <span className="av">GA</span>
      <div style={{ flex: 1, minWidth: 0 }}><div className="en">Graha Asri Residence</div><div className="em">1,240 units · Bekasi</div></div>
      <Icon name="chevrons-up-down" size={16} className="chev" />
    </div>
  );
}

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [route, setRoute] = React.useState(DEFAULT_ROUTE[ROLE]);
  const [navOpen, setNavOpen] = React.useState(false);
  const [complaints, setComplaints] = React.useState(window.HK.complaints.map((c) => ({ ...c })));
  const [announcements, setAnnouncements] = React.useState(window.HK.announcements.map((a) => ({ ...a })));
  const [packages, setPackages] = React.useState(window.HK.packages.map((p) => ({ ...p })));
  const [urunan, setUrunan] = React.useState(window.HK.urunan.map((u) => ({ ...u })));
  const [letters, setLetters] = React.useState(window.HK.letters.map((l) => ({ ...l })));
  const [selId, setSelId] = React.useState(null);
  const [toast, setToast] = React.useState(null);
  const toastTimer = React.useRef(null);

  React.useEffect(() => {
    const root = document.documentElement;
    const a = ACCENTS[t.accent] || ACCENTS.Cyan;
    root.style.setProperty("--accent", a.p);
    root.style.setProperty("--accent-2", a.s);
    root.style.setProperty("--accent-soft", softRgba(a.p, t.dark ? 0.2 : 0.13));
    root.setAttribute("data-theme", t.dark ? "dark" : "light");
    root.setAttribute("data-density", t.density);
  }, [t.accent, t.dark, t.density]);

  const showToast = (msg) => {
    setToast(msg);
    clearTimeout(toastTimer.current);
    toastTimer.current = setTimeout(() => setToast(null), 2600);
  };

  const go = (r) => { setRoute(r); setNavOpen(false); setSelId(null); };

  // helper: kalau persist ke backend gagal, kasih toast (UI optimistic tetap jalan)
  const failToast = (msg) => () => showToast("⚠️ " + msg);

  const ctx = {
    role: ROLE, complaints, announcements, packages, urunan, letters,
    go, toast: showToast,
    openComplaint: (id) => setSelId(id),
    updateComplaint: (id, patch) => {
      setComplaints((cs) => cs.map((c) => c.id === id ? { ...c, ...patch } : c));
      // persist ke backend (PATCH pakai id numerik _id)
      const c = complaints.find((x) => x.id === id);
      if (c && c._id) {
        const body = {};
        if (patch.status) body.status = patch.status;
        // view kirim assignee sbg key ("teknik") -> backend mau nama tim ("Tim Teknik")
        if ("assignee" in patch) body.assignee_team = patch.assignee ? (window.HK.staff[patch.assignee] || {}).name : null;
        if (patch.prio) body.priority = patch.prio;
        window.API.apiPatch("/complaints/" + c._id, body).catch(failToast("Gagal simpan perubahan komplain"));
      }
    },
    addComplaint: (data) => {
      const id = "C-" + (2419 + complaints.length);
      setComplaints((cs) => [{ id, photos: 0, affected: 0, slaMin: 1440, ageMin: 0, assignee: null, tl: [], icon: "message-square-warning",
        reporter: window.HK.me.name, unit: window.HK.me.unit, created: "Baru saja", status: "Open", prio: "normal", ...data }, ...cs]);
      showToast("Laporan terkirim ke pengelola · " + id);
      // backend nentuin unit_id & reporter dari token penghuni
      window.API.apiPost("/complaints", { category: data.cat, title: data.title, description: data.desc, priority: data.prio || "normal", icon: data.icon, location: data.loc })
        .catch(failToast("Laporan belum tersimpan ke server"));
      return id;
    },
    updatePackage: (id, patch) => {
      setPackages((ps) => ps.map((p) => p.id === id ? { ...p, ...patch } : p));
      // satu-satunya aksi paket yg persist: tandai diambil (pickup)
      if (patch.status === "Picked") {
        const p = packages.find((x) => x.id === id);
        if (p && p._id) window.API.apiPost("/packages/" + p._id + "/pickup").catch(failToast("Gagal update status paket"));
      }
    },
    addPackage: (data) => {
      const id = "PKG-" + (7749 + packages.length);
      setPackages((ps) => [{ id, status: "Held", at: "Baru saja", photo: false, note: "", shelf: "Rak A-1",
        receivedBy: "Agus Wijaya", post: "Pos Satpam Utama", code: id.replace("PKG-", ""), ...data }, ...ps]);
      showToast("Paket dicatat · penghuni diberi notifikasi");
      window.API.apiPost("/packages", { recipient_name: data.name, courier: data.courier, size: data.size, post: data.post, note: data.note })
        .catch(failToast("Paket belum tersimpan ke server"));
      return id;
    },
    publish: (a) => {
      setAnnouncements((prev) => [{ id: Date.now(), time: "Just now", author: "You · Estate Manager", reach: 0, total: 1240, pinned: false, ...a }, ...prev]);
      showToast("Announcement published to " + (a.aud || "all residents"));
      window.API.apiPost("/announcements", { type: a.type, title: a.title, body: a.body, channels: a.channels, audience: a.aud || "All residents" })
        .catch(failToast("Pengumuman belum tersimpan ke server"));
    },
    contributeUrunan: (id, amount) => {
      setUrunan((us) => us.map((u) => u.id === id ? { ...u, collected: Math.min(u.target, u.collected + amount), contributors: u.contributors + 1, status: (u.collected + amount) >= u.target ? "Tercapai" : u.status } : u));
      showToast("Terima kasih! Kontribusi " + window.HK.rp(amount) + " tercatat");
      const u = urunan.find((x) => x.id === id);
      if (u && u._id) window.API.apiPost("/contributions/" + u._id + "/contribute", { amount: amount }).catch(failToast("Kontribusi belum tersimpan ke server"));
    },
    addUrunan: (data) => {
      const id = "UR-" + (13 + urunan.length);
      setUrunan((us) => [{ id, collected: 0, contributors: 0, status: "Aktif", ...data }, ...us]);
      showToast("Urunan " + id + " dibuat & diumumkan ke warga");
      let eid = 1; try { eid = JSON.parse(localStorage.getItem("user") || "{}").estate_id || 1; } catch (e) {}
      window.API.apiPost("/contributions", { estate_id: eid, title: data.title, category: data.cat, icon: data.icon, color: data.color, target: data.target, deadline: data.deadline, note: data.note })
        .catch(failToast("Urunan belum tersimpan ke server"));
      return id;
    },
    addLetter: (data) => {
      const id = "SR-" + (232 + letters.length);
      setLetters((ls) => [{ id, status: "Menunggu", date: "Baru saja", unit: window.HK.me.unit, name: window.HK.me.name, ...data }, ...ls]);
      showToast("Pengajuan terkirim · " + id);
      window.API.apiPost("/letters", { type: data.type, detail: data.detail }).catch(failToast("Pengajuan belum tersimpan ke server"));
      return id;
    },
    updateLetter: (id, patch) => {
      setLetters((ls) => ls.map((l) => l.id === id ? { ...l, ...patch } : l));
      const l = letters.find((x) => x.id === id);
      if (l && l._id && patch.status) window.API.apiPatch("/letters/" + l._id, { status: patch.status }).catch(failToast("Gagal update surat di server"));
    },
  };

  const openCount = complaints.filter((c) => c.status !== "Resolved").length;
  const heldPkg = packages.filter((p) => p.status === "Held").length;
  const myHeld = packages.filter((p) => p.status === "Held" && p.unit === window.HK.me.unit).length;
  const counts = { open: openCount, vis: 1, fac: 3, pkg: heldPkg, mypkg: myHeld, bill: window.HK.me.ipl.status === "Lunas" ? 0 : 1, letters: letters.filter((l) => l.status === "Menunggu").length };
  const selected = complaints.find((c) => c.id === selId);

  const View = viewFor(ROLE, route) || (() => <div className="content-inner"><div className="card pad">Halaman tidak tersedia.</div></div>);
  const id = IDENTITY[ROLE];
  const nav = NAV_BY_ROLE[ROLE];
  const title = titleFor(ROLE, route);

  return (
    <div className={"app role-" + ROLE + (navOpen ? " nav-open" : "")}>
      <div className="nav-scrim" onClick={() => setNavOpen(false)} />

      <aside className="sidebar">
        <button className="close-nav" onClick={() => setNavOpen(false)} aria-label="Tutup menu"><Icon name="x" size={18} /></button>
        <div className="brand">
          <span className="mark"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.1" strokeLinecap="round" strokeLinejoin="round"><path d="M3 11.5 12 4l9 7.5" /><path d="M5 10v10h14V10" /><path d="M9.5 20v-5h5v5" /></svg></span>
          <div><div className="nm">Hunian <span>Kita</span></div><div className="sub">{ROLE === "admin" ? "Platform console" : ROLE === "penghuni" ? "Aplikasi warga" : "Management portal"}</div></div>
        </div>

        <EstateCard role={ROLE} />

        {nav.map((group) => (
          <React.Fragment key={group.sec}>
            <div className="navlabel">{group.sec}</div>
            {group.items.map((it) => (
              <button key={it.key} className={"navitem" + (route === it.key ? " active" : "")} onClick={() => go(it.key)}>
                <Icon name={it.icon} size={19} /><span>{it.label}</span>
                {it.badge && counts[it.badge] > 0 && <span className={"count" + (it.badge === "open" || it.badge === "mypkg" || it.badge === "bill" ? "" : " calm")}>{counts[it.badge]}</span>}
              </button>
            ))}
          </React.Fragment>
        ))}

        <div className="sidefoot">
          <button className={"navitem" + (route === "settings" ? " active" : "")} onClick={() => go("settings")}><Icon name="settings" size={19} /><span>{ROLE === "penghuni" ? "Pengaturan" : "Settings"}</span></button>
          <div className="userchip" style={{ marginTop: 8 }}>
            <Avatar name={id.name} size={32} />
            <div style={{ flex: 1, minWidth: 0 }}><div className="nm">{id.name}</div><div className="role">{id.role}</div></div>
            <a href="#" title="Keluar" onClick={(e) => { e.preventDefault(); window.API.logout(); }} style={{ display: "grid", placeItems: "center", color: "var(--t3)" }}><Icon name="log-out" size={16} /></a>
          </div>
        </div>
      </aside>

      <main className="main">
        <header className="topbar">
          <button className="hamburger" onClick={() => setNavOpen(true)} aria-label="Buka menu"><Icon name="menu" size={20} /></button>
          <div className="mbrand"><span className="mark"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.1" strokeLinecap="round" strokeLinejoin="round"><path d="M3 11.5 12 4l9 7.5" /><path d="M5 10v10h14V10" /><path d="M9.5 20v-5h5v5" /></svg></span>Hunian <span>Kita</span></div>
          <div className="ttl"><h1>{title[0]}</h1><p>{title[1]}</p></div>
          <div className="search"><Icon name="search" size={16} /><input placeholder={ROLE === "penghuni" ? "Cari…" : "Search units, residents, tickets…"} /></div>
          <button className="iconbtn"><Icon name="bell" size={18} /><span className="dot" /></button>
          {ROLE !== "penghuni" && <button className="iconbtn"><Icon name="circle-help" size={18} /></button>}
        </header>
        <div className="content"><View ctx={ctx} /></div>
      </main>

      {ROLE === "penghuni" && (
        <nav className="bottomnav">
          {BOTTOM.map((b) => (
            <button key={b.key} className={(b.key !== "more" && route === b.key) ? "active" : ""} onClick={() => b.key === "more" ? setNavOpen(true) : go(b.key)}>
              {b.badge && counts[b.badge] > 0 && <span className="nv-badge">{counts[b.badge]}</span>}
              <Icon name={b.icon} size={22} /><span>{b.label}</span>
            </button>
          ))}
        </nav>
      )}

      {selected && <ComplaintDrawer c={selected} ctx={ctx} onClose={() => setSelId(null)} />}
      <Toast msg={toast} />

      <TweaksPanel>
        <TweakSection label="Theme" />
        <TweakToggle label="Dark mode" value={t.dark} onChange={(v) => setTweak("dark", v)} />
        <div className="tw-accents">
          {Object.entries(ACCENTS).map(([name, a]) => (
            <button key={name} className={"tw-acc" + (t.accent === name ? " on" : "")} onClick={() => setTweak("accent", name)}
              style={{ background: `linear-gradient(135deg, ${a.p}, ${a.s})` }} title={name}>
              {t.accent === name && <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="#fff" strokeWidth="3.4" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6 9 17l-5-5" /></svg>}
            </button>
          ))}
        </div>
        <TweakSection label="Layout" />
        <TweakRadio label="Density" value={t.density} options={["compact", "regular", "comfy"]} onChange={(v) => setTweak("density", v)} />
      </TweaksPanel>
    </div>
  );
}

// boot: fetch data asli dari backend DULU (timpa window.HK), baru render React.
// kalau gagal (server mati / dll) tetap render pakai data lama biar nggak blank.
async function boot() {
  try {
    await window.API.loadAll();
  } catch (err) {
    // catatan: kalau errornya 401, API.loadAll udah nendang ke halaman login,
    // jadi di sini cukup log aja & lanjut render apa adanya.
    console.warn("[BOOT] gagal muat data backend, pakai data dummy dulu:", err.message);
  }
  ReactDOM.createRoot(document.getElementById("root")).render(<App />);
}
boot();
