/* Admin Panel Views: Clients, Machines, Billing, Invoices */
const { useState: useStateAdmin, useMemo: useMemoAdmin } = React;

/* ═══════════════════════════════════════════════
   ADMIN: DAFTAR CLIENT
   ═══════════════════════════════════════════════ */
function AdminClientsView() {
  const { users, setUsers, allMachines, invoices, navigate, toast } = useApp();
  const clients = users.filter(u => u.role === "client");

  const [search, setSearch]     = useStateAdmin("");
  const [showAdd, setShowAdd]   = useStateAdmin(false);
  const [showEdit, setShowEdit] = useStateAdmin(null); // client object
  const [newClient, setNewClient] = useStateAdmin({ name:"", email:"", password:"", phone:"", address:"" });

  const filtered = clients.filter(c =>
    c.name.toLowerCase().includes(search.toLowerCase()) ||
    c.email.toLowerCase().includes(search.toLowerCase())
  );

  function addClient(e) {
    e.preventDefault();
    if (!newClient.name || !newClient.email || !newClient.password) {
      toast("Lengkapi semua field wajib.", "danger"); return;
    }
    if (users.find(u => u.email === newClient.email)) {
      toast("Email sudah terdaftar.", "danger"); return;
    }
    const id = "client-" + Date.now();
    const created = {
      ...newClient,
      id,
      role: "client",
      joined: new Date().toLocaleDateString("id-ID", { day:"numeric", month:"long", year:"numeric" }),
    };
    setUsers(prev => [...prev, created]);
    setNewClient({ name:"", email:"", password:"", phone:"", address:"" });
    setShowAdd(false);
    toast(`Client ${newClient.name} berhasil ditambahkan.`, "success");
    db.upsertUser(created).catch(err => toast("Gagal simpan ke Supabase: " + err.message, "danger"));
  }

  function updateClient(e) {
    e.preventDefault();
    const updated = showEdit;
    setUsers(prev => prev.map(u => u.id === updated.id ? updated : u));
    setShowEdit(null);
    toast("Data client berhasil diupdate.", "success");
    db.upsertUser(updated).catch(err => toast("Gagal simpan ke Supabase: " + err.message, "danger"));
  }

  function deleteClient(id) {
    if (!window.confirm("Hapus client ini? Data mesin terkait tidak akan terhapus.")) return;
    setUsers(prev => prev.filter(u => u.id !== id));
    toast("Client dihapus.", "info");
    db.deleteUser(id).catch(err => toast("Gagal hapus di Supabase: " + err.message, "danger"));
  }

  function clientMachineCount(clientId) {
    return allMachines.filter(m => m.clientId === clientId).length;
  }

  return (
    <div className="px-5 md:px-8 py-7 md:py-9 max-w-6xl mx-auto">
      <PageHeader
        eyebrow="Admin" jp="クライアント管理" title="Daftar Client"
        sub={`${clients.length} client terdaftar`}
        actions={
          <Button onClick={() => setShowAdd(true)} variant="primary">
            <Icon name="plus" size={16}/> Tambah Client
          </Button>
        }
      />

      {/* Search */}
      <div className="relative mb-5 max-w-sm">
        <Icon name="search" size={16} className="absolute left-3 top-1/2 -translate-y-1/2 text-stone-400"/>
        <input
          type="text" value={search} onChange={e => setSearch(e.target.value)}
          placeholder="Cari nama atau email..."
          className="w-full pl-9 pr-4 py-2.5 rounded-xl border border-stone-300 bg-white text-sm focus:border-[#FF2D55] focus:ring-2 focus:ring-pink-100 outline-none"
        />
      </div>

      {/* Table */}
      <Card className="overflow-hidden">
        <div className="overflow-x-auto">
          <table className="w-full text-sm">
            <thead>
              <tr className="bg-stone-50 border-b border-stone-200 text-[11px] font-bold uppercase tracking-widest text-stone-500">
                <th className="px-5 py-3 text-left">Client</th>
                <th className="px-5 py-3 text-left hidden md:table-cell">Kontak</th>
                <th className="px-5 py-3 text-center">Mesin</th>
                <th className="px-5 py-3 text-left hidden lg:table-cell">Bergabung</th>
                <th className="px-5 py-3 text-right">Aksi</th>
              </tr>
            </thead>
            <tbody>
              {filtered.map(c => (
                <tr key={c.id} className="border-b border-stone-100 last:border-0 hover:bg-stone-50/50">
                  <td className="px-5 py-4">
                    <div className="flex items-center gap-3">
                      <div className="w-9 h-9 rounded-full bg-[#FF2D55] text-white flex items-center justify-center font-bold text-sm flex-none">
                        {c.name.charAt(0)}
                      </div>
                      <div>
                        <div className="font-semibold text-[#1A1A1A]">{c.name}</div>
                        <div className="text-xs text-stone-500">{c.email}</div>
                      </div>
                    </div>
                  </td>
                  <td className="px-5 py-4 hidden md:table-cell text-stone-600">{c.phone || "—"}</td>
                  <td className="px-5 py-4 text-center">
                    <span className="inline-flex items-center justify-center w-7 h-7 rounded-full bg-pink-50 text-[#FF2D55] font-bold text-sm">
                      {clientMachineCount(c.id)}
                    </span>
                  </td>
                  <td className="px-5 py-4 hidden lg:table-cell text-stone-500 text-xs">{c.joined}</td>
                  <td className="px-5 py-4">
                    <div className="flex items-center justify-end gap-1">
                      <button onClick={() => setShowEdit({ ...c })}
                        className="p-2 rounded-lg text-stone-400 hover:bg-stone-100 hover:text-[#FF2D55]">
                        <Icon name="edit" size={15}/>
                      </button>
                      <button onClick={() => deleteClient(c.id)}
                        className="p-2 rounded-lg text-stone-400 hover:bg-rose-50 hover:text-rose-600">
                        <Icon name="trash" size={15}/>
                      </button>
                    </div>
                  </td>
                </tr>
              ))}
              {filtered.length === 0 && (
                <tr><td colSpan={5} className="px-5 py-10 text-center text-stone-400 text-sm">Tidak ada client ditemukan.</td></tr>
              )}
            </tbody>
          </table>
        </div>
      </Card>

      {/* Add Client Modal */}
      <Modal open={showAdd} onClose={() => setShowAdd(false)} title="Tambah Client Baru">
        <form onSubmit={addClient} className="space-y-4">
          <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
            <Field label="Nama Lengkap *" value={newClient.name} onChange={v => setNewClient({...newClient, name:v})} required/>
            <Field label="Email *" type="email" value={newClient.email} onChange={v => setNewClient({...newClient, email:v})} required/>
            <Field label="Password *" type="password" value={newClient.password} onChange={v => setNewClient({...newClient, password:v})} required/>
            <Field label="Nomor HP" value={newClient.phone} onChange={v => setNewClient({...newClient, phone:v})}/>
            <Field label="Alamat" value={newClient.address} onChange={v => setNewClient({...newClient, address:v})} full/>
          </div>
          <div className="flex gap-2 pt-2">
            <Button type="submit" variant="primary">Simpan Client</Button>
            <Button type="button" variant="subtle" onClick={() => setShowAdd(false)}>Batal</Button>
          </div>
        </form>
      </Modal>

      {/* Edit Client Modal */}
      {showEdit && (
        <Modal open={!!showEdit} onClose={() => setShowEdit(null)} title="Edit Client">
          <form onSubmit={updateClient} className="space-y-4">
            <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
              <Field label="Nama Lengkap" value={showEdit.name} onChange={v => setShowEdit({...showEdit, name:v})}/>
              <Field label="Email" type="email" value={showEdit.email} onChange={v => setShowEdit({...showEdit, email:v})}/>
              <Field label="Password Baru" type="password" value={showEdit.password} onChange={v => setShowEdit({...showEdit, password:v})} placeholder="Kosongkan jika tidak diubah"/>
              <Field label="Nomor HP" value={showEdit.phone || ""} onChange={v => setShowEdit({...showEdit, phone:v})}/>
              <Field label="Alamat" value={showEdit.address || ""} onChange={v => setShowEdit({...showEdit, address:v})} full/>
            </div>
            <div className="flex gap-2 pt-2">
              <Button type="submit" variant="primary">Simpan Perubahan</Button>
              <Button type="button" variant="subtle" onClick={() => setShowEdit(null)}>Batal</Button>
            </div>
          </form>
        </Modal>
      )}
    </div>
  );
}

/* ═══════════════════════════════════════════════
   ADMIN: STATUS MESIN
   ═══════════════════════════════════════════════ */
function AdminMachinesView() {
  const { allMachines, setMachines, users, navigate, toast } = useApp();
  const [filter, setFilter] = useStateAdmin("all");
  const [search, setSearch] = useStateAdmin("");
  const [showEdit, setShowEdit]     = useStateAdmin(null);
  const [showAssign, setShowAssign] = useStateAdmin(null); // machine to assign
  const [assignTo, setAssignTo]     = useStateAdmin("");
  const [showAdd, setShowAdd]       = useStateAdmin(false);
  const [newMachine, setNewMachine] = useStateAdmin({
    id: "", model: "", type: "", category: "combo",
    location: "", status: "Aktif", scheme: "Sewa",
    contractStart: new Date().toISOString().split("T")[0],
    contractEnd: "", minContract: 6,
    rates: { sewa: 2500000, cloud: 350000, refill: 0, cloudApi: 0 },
    addons: { cloud: true, refill: false, cloudApi: false },
    color: "#FFD9E0",
    clientId: "",
  });

  const clients = users.filter(u => u.role === "client");

  const COLOR_OPTIONS = [
    { hex: "#FFD9E0", name: "Pink" },
    { hex: "#FFE9A8", name: "Kuning" },
    { hex: "#D0F0FF", name: "Biru" },
    { hex: "#D4F4DD", name: "Hijau" },
    { hex: "#F0E0FF", name: "Ungu" },
    { hex: "#FFD9C2", name: "Oranye" },
  ];

  const filtered = useMemoAdmin(() => {
    let list = allMachines;
    if (filter !== "all") {
      list = list.filter(m => {
        const tone = statusForMachine(m).tone;
        return (filter === "active" && tone === "success") ||
               (filter === "expiring" && tone === "warning") ||
               (filter === "expired" && tone === "danger");
      });
    }
    if (search) {
      list = list.filter(m =>
        m.id.toLowerCase().includes(search.toLowerCase()) ||
        m.model.toLowerCase().includes(search.toLowerCase()) ||
        m.location.toLowerCase().includes(search.toLowerCase())
      );
    }
    return list;
  }, [allMachines, filter, search]);

  function saveEdit(e) {
    e.preventDefault();
    const updated = showEdit;
    setMachines(prev => prev.map(m => m.id === updated.id ? updated : m));
    setShowEdit(null);
    toast("Data mesin berhasil diupdate.", "success");
    db.upsertMachine(updated).catch(err => toast("Gagal simpan ke Supabase: " + err.message, "danger"));
  }

  function openAssign(machine) {
    setAssignTo(machine.clientId || "");
    setShowAssign(machine);
  }

  function saveAssign(e) {
    e.preventDefault();
    if (!assignTo) { toast("Pilih client terlebih dahulu.", "danger"); return; }
    const target = clients.find(c => c.id === assignTo);
    const updated = { ...showAssign, clientId: assignTo };
    setMachines(prev => prev.map(m => m.id === updated.id ? updated : m));
    toast(`${updated.id} di-assign ke ${target?.name || assignTo}.`, "success");
    setShowAssign(null);
    setAssignTo("");
    db.upsertMachine(updated).catch(err => toast("Gagal simpan ke Supabase: " + err.message, "danger"));
  }

  function addMachine(e) {
    e.preventDefault();
    if (!newMachine.id || !newMachine.model || !newMachine.location || !newMachine.clientId || !newMachine.contractEnd) {
      toast("Lengkapi: ID, model, lokasi, client, dan tanggal berakhir.", "danger"); return;
    }
    if (allMachines.find(m => m.id === newMachine.id)) {
      toast("ID mesin sudah dipakai.", "danger"); return;
    }
    const monthly = Object.entries(newMachine.rates).reduce((sum, [k, v]) =>
      sum + ((k === "sewa" || newMachine.addons[k]) ? Number(v) : 0), 0);
    const created = {
      ...newMachine,
      monthlyRevenue: monthly,
      salesThisMonth: 0,
      transactionsThisMonth: 0,
      payments: [],
    };
    setMachines(prev => [...prev, created]);
    toast(`Mesin ${newMachine.id} berhasil ditambahkan.`, "success");
    setShowAdd(false);
    db.upsertMachine(created).catch(err => toast("Gagal simpan ke Supabase: " + err.message, "danger"));
    setNewMachine({
      id: "", model: "", type: "", category: "combo",
      location: "", status: "Aktif", scheme: "Sewa",
      contractStart: new Date().toISOString().split("T")[0],
      contractEnd: "", minContract: 6,
      rates: { sewa: 2500000, cloud: 350000, refill: 0, cloudApi: 0 },
      addons: { cloud: true, refill: false, cloudApi: false },
      color: "#FFD9E0",
      clientId: "",
    });
  }

  const getClient = (cid) => users.find(u => u.id === cid);

  return (
    <div className="px-5 md:px-8 py-7 md:py-9 max-w-7xl mx-auto">
      <PageHeader
        eyebrow="Admin" jp="マシン管理" title="Status Mesin"
        sub={`${allMachines.length} mesin terpasang · ${allMachines.filter(m => statusForMachine(m).tone === "warning").length} mendekati expired`}
        actions={
          <Button onClick={() => setShowAdd(true)} variant="primary">
            <Icon name="plus" size={16}/> Tambah Mesin Baru
          </Button>
        }
      />

      {/* Filters */}
      <div className="flex flex-wrap items-center gap-3 mb-5">
        <div className="relative">
          <Icon name="search" size={15} className="absolute left-3 top-1/2 -translate-y-1/2 text-stone-400"/>
          <input type="text" value={search} onChange={e => setSearch(e.target.value)}
            placeholder="Cari mesin..."
            className="pl-8 pr-4 py-2 rounded-xl border border-stone-300 bg-white text-sm focus:border-[#FF2D55] outline-none"/>
        </div>
        {["all","active","expiring","expired"].map(f => (
          <button key={f} onClick={() => setFilter(f)}
            className={`px-4 py-2 rounded-full text-sm font-semibold transition ${filter === f ? "bg-[#1A1A1A] text-white" : "bg-white border border-stone-200 text-stone-700 hover:border-[#FF2D55] hover:text-[#FF2D55]"}`}>
            {f === "all" ? "Semua" : f === "active" ? "Aktif" : f === "expiring" ? "Akan Berakhir" : "Expired"}
          </button>
        ))}
      </div>

      {/* Table */}
      <Card className="overflow-hidden">
        <div className="overflow-x-auto">
          <table className="w-full text-sm">
            <thead>
              <tr className="bg-stone-50 border-b border-stone-200 text-[11px] font-bold uppercase tracking-widest text-stone-500">
                <th className="px-5 py-3 text-left">Mesin</th>
                <th className="px-5 py-3 text-left hidden md:table-cell">Client</th>
                <th className="px-5 py-3 text-left hidden lg:table-cell">Lokasi</th>
                <th className="px-5 py-3 text-center">Status</th>
                <th className="px-5 py-3 text-left hidden lg:table-cell">Kontrak</th>
                <th className="px-5 py-3 text-right hidden md:table-cell">Billing</th>
                <th className="px-5 py-3 text-right">Aksi</th>
              </tr>
            </thead>
            <tbody>
              {filtered.map(m => {
                const s = statusForMachine(m);
                const client = getClient(m.clientId);
                return (
                  <tr key={m.id} className="border-b border-stone-100 last:border-0 hover:bg-stone-50/50">
                    <td className="px-5 py-4">
                      <div className="flex items-center gap-3">
                        <div className="w-10 h-10 rounded-xl flex items-center justify-center flex-none" style={{ background: m.color }}>
                          <Icon name={m.category === "coffee" ? "coffee" : m.category === "frozen" ? "thermometer" : "grid"} size={18} className="text-[#1A1A1A]"/>
                        </div>
                        <div>
                          <div className="font-semibold text-[#1A1A1A]">{m.id}</div>
                          <div className="text-xs text-stone-500">{m.model}</div>
                        </div>
                      </div>
                    </td>
                    <td className="px-5 py-4 hidden md:table-cell">
                      <div className="font-medium text-[#1A1A1A]">{client?.name || "—"}</div>
                      <div className="text-xs text-stone-500">{client?.email}</div>
                    </td>
                    <td className="px-5 py-4 hidden lg:table-cell text-stone-600 text-xs max-w-[180px] truncate">{m.location}</td>
                    <td className="px-5 py-4 text-center">
                      <Badge tone={s.tone}>{s.tone === "success" ? "Aktif" : s.tone === "warning" ? "Akan Berakhir" : "Expired"}</Badge>
                      <div className="text-[10px] text-stone-400 mt-1">{s.label}</div>
                    </td>
                    <td className="px-5 py-4 hidden lg:table-cell">
                      <div className="text-xs text-stone-500">Berakhir</div>
                      <div className="font-medium text-[#1A1A1A]">{formatDateID(m.contractEnd)}</div>
                    </td>
                    <td className="px-5 py-4 hidden md:table-cell text-right">
                      <div className="font-display text-base text-[#FF2D55]">{formatRp(m.monthlyRevenue)}</div>
                      <div className="text-[10px] text-stone-400">/bulan</div>
                    </td>
                    <td className="px-5 py-4">
                      <div className="flex items-center justify-end gap-1">
                        <button onClick={() => openAssign(m)} title="Assign Client"
                          className="p-2 rounded-lg text-stone-400 hover:bg-stone-100 hover:text-[#FF2D55]">
                          <Icon name="user" size={15}/>
                        </button>
                        <button onClick={() => setShowEdit({ ...m })} title="Edit"
                          className="p-2 rounded-lg text-stone-400 hover:bg-stone-100 hover:text-[#FF2D55]">
                          <Icon name="edit" size={15}/>
                        </button>
                      </div>
                    </td>
                  </tr>
                );
              })}
              {filtered.length === 0 && (
                <tr><td colSpan={7} className="px-5 py-10 text-center text-stone-400 text-sm">Tidak ada mesin ditemukan.</td></tr>
              )}
            </tbody>
          </table>
        </div>
      </Card>

      {/* Edit Machine Modal */}
      {showEdit && (
        <Modal open={!!showEdit} onClose={() => setShowEdit(null)} title={`Edit Mesin ${showEdit.id}`} width="max-w-2xl">
          <form onSubmit={saveEdit} className="space-y-4">
            <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
              <Field label="Lokasi" value={showEdit.location} onChange={v => setShowEdit({...showEdit, location:v})} full/>
              <div>
                <label className="text-[11px] font-bold uppercase tracking-widest text-stone-500">Assign Client</label>
                <select value={showEdit.clientId} onChange={e => setShowEdit({...showEdit, clientId: e.target.value})}
                  className="mt-1.5 w-full px-4 py-2.5 rounded-xl border border-stone-300 bg-white text-[#1A1A1A] focus:border-[#FF2D55] outline-none">
                  {clients.map(c => <option key={c.id} value={c.id}>{c.name}</option>)}
                </select>
              </div>
              <div>
                <label className="text-[11px] font-bold uppercase tracking-widest text-stone-500">Status</label>
                <select value={showEdit.status} onChange={e => setShowEdit({...showEdit, status: e.target.value})}
                  className="mt-1.5 w-full px-4 py-2.5 rounded-xl border border-stone-300 bg-white text-[#1A1A1A] focus:border-[#FF2D55] outline-none">
                  <option>Aktif</option>
                  <option>Nonaktif</option>
                  <option>Maintenance</option>
                </select>
              </div>
              <Field label="Tanggal Berakhir Kontrak" type="date" value={showEdit.contractEnd} onChange={v => setShowEdit({...showEdit, contractEnd:v})}/>
              <Field label="Skema" value={showEdit.scheme} onChange={v => setShowEdit({...showEdit, scheme:v})}/>
            </div>

            <div className="pt-2 border-t border-stone-100">
              <div className="text-[11px] font-bold uppercase tracking-widest text-stone-500 mb-3">Harga Bulanan (Rp)</div>
              <div className="grid grid-cols-2 md:grid-cols-4 gap-3">
                {["sewa","cloud","refill","cloudApi"].map(key => (
                  <div key={key}>
                    <label className="text-[10px] font-bold uppercase tracking-widest text-stone-500 capitalize">{key}</label>
                    <input type="number" value={showEdit.rates[key]}
                      onChange={e => setShowEdit({...showEdit, rates:{...showEdit.rates, [key]: Number(e.target.value)}})}
                      className="mt-1 w-full px-3 py-2 rounded-xl border border-stone-300 bg-white text-sm focus:border-[#FF2D55] outline-none"/>
                  </div>
                ))}
              </div>
            </div>

            <div className="flex gap-2 pt-2">
              <Button type="submit" variant="primary">Simpan Perubahan</Button>
              <Button type="button" variant="subtle" onClick={() => setShowEdit(null)}>Batal</Button>
            </div>
          </form>
        </Modal>
      )}

      {/* Assign Client Modal */}
      {showAssign && (
        <Modal open={!!showAssign} onClose={() => { setShowAssign(null); setAssignTo(""); }}
          title={`Assign Client — ${showAssign.id}`}>
          <form onSubmit={saveAssign} className="space-y-4">
            <div className="flex items-center gap-3 p-3 rounded-xl bg-stone-50 border border-stone-100">
              <div className="w-12 h-12 rounded-xl flex items-center justify-center flex-none" style={{ background: showAssign.color }}>
                <Icon name={showAssign.category === "coffee" ? "coffee" : showAssign.category === "frozen" ? "thermometer" : "grid"} size={20} className="text-[#1A1A1A]"/>
              </div>
              <div>
                <div className="font-semibold text-[#1A1A1A] text-sm">{showAssign.model}</div>
                <div className="text-xs text-stone-500">{showAssign.location}</div>
                <div className="text-xs text-stone-400 mt-0.5">
                  Saat ini: {getClient(showAssign.clientId)?.name || <span className="text-stone-400 italic">Belum di-assign</span>}
                </div>
              </div>
            </div>

            <div>
              <label className="text-[11px] font-bold uppercase tracking-widest text-stone-500">Pilih Client *</label>
              <select value={assignTo} onChange={e => setAssignTo(e.target.value)}
                className="mt-1.5 w-full px-4 py-2.5 rounded-xl border border-stone-300 bg-white text-[#1A1A1A] focus:border-[#FF2D55] focus:ring-2 focus:ring-pink-100 outline-none transition">
                <option value="">— Pilih client —</option>
                {clients.map(c => (
                  <option key={c.id} value={c.id}>{c.name} ({c.email})</option>
                ))}
              </select>
              {clients.length === 0 && (
                <div className="text-xs text-amber-600 mt-2">Belum ada client. Buat client dulu di menu Daftar Client.</div>
              )}
            </div>

            <div className="flex gap-2 pt-2">
              <Button type="submit" variant="primary" disabled={!assignTo || assignTo === showAssign.clientId}>
                Simpan Assignment
              </Button>
              <Button type="button" variant="subtle" onClick={() => { setShowAssign(null); setAssignTo(""); }}>Batal</Button>
            </div>
          </form>
        </Modal>
      )}

      {/* Add New Machine Modal */}
      <Modal open={showAdd} onClose={() => setShowAdd(false)} title="Tambah Mesin Baru" width="max-w-3xl">
        <form onSubmit={addMachine} className="space-y-5">
          <div>
            <div className="text-[11px] font-bold uppercase tracking-widest text-stone-500 mb-3">Identitas Mesin</div>
            <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
              <Field label="ID Mesin * (cth: YCV-10C-004)" value={newMachine.id} onChange={v => setNewMachine({...newMachine, id: v.toUpperCase()})} required/>
              <Field label="Model * (cth: YAPPARI YCV-10C)" value={newMachine.model} onChange={v => setNewMachine({...newMachine, model: v})} required/>
              <Field label="Tipe (cth: Refrigerated Combo)" value={newMachine.type} onChange={v => setNewMachine({...newMachine, type: v})}/>
              <div>
                <label className="text-[11px] font-bold uppercase tracking-widest text-stone-500">Kategori</label>
                <select value={newMachine.category} onChange={e => setNewMachine({...newMachine, category: e.target.value})}
                  className="mt-1.5 w-full px-4 py-2.5 rounded-xl border border-stone-300 bg-white text-[#1A1A1A] focus:border-[#FF2D55] outline-none">
                  <option value="combo">Combo (Food & Beverage)</option>
                  <option value="coffee">Coffee</option>
                  <option value="frozen">Frozen / Ice Cream</option>
                </select>
              </div>
              <Field label="Lokasi *" value={newMachine.location} onChange={v => setNewMachine({...newMachine, location: v})} required full/>
              <div>
                <label className="text-[11px] font-bold uppercase tracking-widest text-stone-500">Warna Kartu</label>
                <div className="mt-1.5 flex gap-2 flex-wrap">
                  {COLOR_OPTIONS.map(c => (
                    <button type="button" key={c.hex}
                      onClick={() => setNewMachine({...newMachine, color: c.hex})}
                      title={c.name}
                      className={`w-9 h-9 rounded-xl border-2 transition ${newMachine.color === c.hex ? "border-[#1A1A1A] scale-110" : "border-transparent"}`}
                      style={{ background: c.hex }}/>
                  ))}
                </div>
              </div>
              <div>
                <label className="text-[11px] font-bold uppercase tracking-widest text-stone-500">Client *</label>
                <select value={newMachine.clientId} onChange={e => setNewMachine({...newMachine, clientId: e.target.value})}
                  className="mt-1.5 w-full px-4 py-2.5 rounded-xl border border-stone-300 bg-white text-[#1A1A1A] focus:border-[#FF2D55] outline-none">
                  <option value="">— Pilih client —</option>
                  {clients.map(c => <option key={c.id} value={c.id}>{c.name}</option>)}
                </select>
              </div>
            </div>
          </div>

          <div className="pt-4 border-t border-stone-100">
            <div className="text-[11px] font-bold uppercase tracking-widest text-stone-500 mb-3">Kontrak</div>
            <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
              <div>
                <label className="text-[11px] font-bold uppercase tracking-widest text-stone-500">Skema</label>
                <select value={newMachine.scheme} onChange={e => setNewMachine({...newMachine, scheme: e.target.value})}
                  className="mt-1.5 w-full px-4 py-2.5 rounded-xl border border-stone-300 bg-white text-[#1A1A1A] focus:border-[#FF2D55] outline-none">
                  <option>Sewa</option>
                  <option>Beli Putus</option>
                  <option>Revenue Share</option>
                </select>
              </div>
              <Field label="Mulai Kontrak" type="date" value={newMachine.contractStart} onChange={v => setNewMachine({...newMachine, contractStart: v})}/>
              <Field label="Berakhir Kontrak *" type="date" value={newMachine.contractEnd} onChange={v => setNewMachine({...newMachine, contractEnd: v})} required/>
            </div>
          </div>

          <div className="pt-4 border-t border-stone-100">
            <div className="text-[11px] font-bold uppercase tracking-widest text-stone-500 mb-3">Harga Bulanan (Rp)</div>
            <div className="grid grid-cols-2 md:grid-cols-4 gap-3">
              {[
                { key: "sewa",     label: "Sewa Pokok", always: true  },
                { key: "cloud",    label: "Cloud / Dashboard" },
                { key: "refill",   label: "Refill" },
                { key: "cloudApi", label: "Cloud API" },
              ].map(({key, label, always}) => (
                <div key={key}>
                  <label className="text-[10px] font-bold uppercase tracking-widest text-stone-500">{label}</label>
                  <input type="number" value={newMachine.rates[key]}
                    onChange={e => setNewMachine({...newMachine, rates:{...newMachine.rates, [key]: Number(e.target.value)}})}
                    className="mt-1 w-full px-3 py-2 rounded-xl border border-stone-300 bg-white text-sm focus:border-[#FF2D55] outline-none"/>
                  {!always && (
                    <label className="mt-1.5 flex items-center gap-1.5 text-xs text-stone-500 cursor-pointer">
                      <input type="checkbox" checked={newMachine.addons[key]}
                        onChange={e => setNewMachine({...newMachine, addons: {...newMachine.addons, [key]: e.target.checked}})}/>
                      Aktif
                    </label>
                  )}
                </div>
              ))}
            </div>
            <div className="mt-3 text-xs text-stone-500">
              Total / bulan: <span className="font-display text-base text-[#FF2D55]">
                {formatRp(Object.entries(newMachine.rates).reduce((s,[k,v]) =>
                  s + ((k === "sewa" || newMachine.addons[k]) ? Number(v) : 0), 0))}
              </span>
            </div>
          </div>

          <div className="flex gap-2 pt-2">
            <Button type="submit" variant="primary">Simpan Mesin</Button>
            <Button type="button" variant="subtle" onClick={() => setShowAdd(false)}>Batal</Button>
          </div>
        </form>
      </Modal>
    </div>
  );
}

/* ═══════════════════════════════════════════════
   ADMIN: BILLING
   ═══════════════════════════════════════════════ */
function AdminBillingView() {
  const { allMachines, users, invoices, setInvoices, toast } = useApp();
  const clients = users.filter(u => u.role === "client");

  const totalMonthly = allMachines.reduce((s, m) => s + m.monthlyRevenue, 0);
  const totalCollected = invoices.reduce((s, i) => s + (i.status === "Lunas" ? i.amount : 0), 0);
  const outstanding = invoices.reduce((s, i) => s + (i.status !== "Lunas" ? i.amount : 0), 0);

  function markPaid(invId) {
    const target = invoices.find(i => i.id === invId);
    if (!target) return;
    const updated = { ...target, status: "Lunas" };
    setInvoices(prev => prev.map(i => i.id === invId ? updated : i));
    toast("Invoice ditandai Lunas.", "success");
    db.upsertInvoice(updated).catch(err => toast("Gagal simpan ke Supabase: " + err.message, "danger"));
  }

  return (
    <div className="px-5 md:px-8 py-7 md:py-9 max-w-6xl mx-auto">
      <PageHeader eyebrow="Admin" jp="請求管理" title="Billing"
        sub="Rekap tagihan dan status pembayaran seluruh client."
      />

      {/* Summary */}
      <div className="grid grid-cols-1 sm:grid-cols-3 gap-4 mb-8">
        <StatCard label="Pendapatan / Bulan" value={"Rp" + (totalMonthly/1000000).toFixed(1) + "Jt"} sub={`${allMachines.length} mesin aktif`} icon="trending" accent="bg-emerald-50 text-emerald-700"/>
        <StatCard label="Total Terkumpul" value={"Rp" + (totalCollected/1000000).toFixed(1) + "Jt"} sub={`${invoices.filter(i => i.status === "Lunas").length} invoice lunas`} icon="wallet" accent="bg-sky-50 text-sky-700"/>
        <StatCard label="Outstanding" value={outstanding > 0 ? "Rp" + (outstanding/1000000).toFixed(1) + "Jt" : "Nihil"} sub={`${invoices.filter(i => i.status !== "Lunas").length} invoice pending`} icon="alertCircle" accent={outstanding > 0 ? "bg-amber-50 text-amber-700" : "bg-emerald-50 text-emerald-700"}/>
      </div>

      {/* Per-client billing breakdown */}
      <div className="space-y-4">
        {clients.map(c => {
          const cMachines = allMachines.filter(m => m.clientId === c.id);
          const cInvoices = invoices.filter(i => i.clientId === c.id);
          const cTotal    = cMachines.reduce((s, m) => s + m.monthlyRevenue, 0);
          if (cMachines.length === 0) return null;

          return (
            <Card key={c.id} className="overflow-hidden">
              <div className="px-6 py-4 bg-stone-50 border-b border-stone-200 flex flex-wrap items-center justify-between gap-3">
                <div className="flex items-center gap-3">
                  <div className="w-9 h-9 rounded-full bg-[#FF2D55] text-white flex items-center justify-center font-bold">{c.name.charAt(0)}</div>
                  <div>
                    <div className="font-semibold text-[#1A1A1A]">{c.name}</div>
                    <div className="text-xs text-stone-500">{c.email} · {cMachines.length} mesin</div>
                  </div>
                </div>
                <div className="text-right">
                  <div className="text-[11px] text-stone-500">Total / bulan</div>
                  <div className="font-display text-xl text-[#FF2D55]">{formatRp(cTotal)}</div>
                </div>
              </div>

              {/* Machine breakdown */}
              <div className="divide-y divide-stone-100">
                {cMachines.map(m => {
                  const s = statusForMachine(m);
                  return (
                    <div key={m.id} className="px-6 py-4 flex flex-wrap items-center justify-between gap-3">
                      <div className="flex items-center gap-3">
                        <div className="w-8 h-8 rounded-lg flex items-center justify-center" style={{ background: m.color }}>
                          <Icon name={m.category === "coffee" ? "coffee" : "grid"} size={16} className="text-[#1A1A1A]"/>
                        </div>
                        <div>
                          <div className="font-medium text-[#1A1A1A] text-sm">{m.id}</div>
                          <div className="text-xs text-stone-500">{m.location}</div>
                        </div>
                      </div>
                      <div className="flex items-center gap-4">
                        <Badge tone={s.tone}>{s.tone === "success" ? "Aktif" : s.tone === "warning" ? "Expiring" : "Expired"}</Badge>
                        <div className="text-sm font-semibold text-[#1A1A1A]">{formatRp(m.monthlyRevenue)}<span className="text-xs text-stone-400 font-normal">/bln</span></div>
                      </div>
                    </div>
                  );
                })}
              </div>

              {/* Recent invoices for this client */}
              {cInvoices.length > 0 && (
                <div className="px-6 py-4 bg-stone-50 border-t border-stone-100">
                  <div className="text-[11px] font-bold uppercase tracking-widest text-stone-500 mb-3">Invoice Terbaru</div>
                  <div className="space-y-2">
                    {cInvoices.slice(0, 3).map(inv => (
                      <div key={inv.id} className="flex items-center justify-between text-sm">
                        <div className="flex items-center gap-2">
                          <span className="font-mono text-xs text-stone-500">{inv.id}</span>
                          <span className="text-stone-600">{inv.period}</span>
                        </div>
                        <div className="flex items-center gap-3">
                          <span className="font-semibold text-[#1A1A1A]">{formatRp(inv.amount)}</span>
                          {inv.status === "Lunas"
                            ? <Badge tone="success">Lunas</Badge>
                            : <button onClick={() => markPaid(inv.id)}
                                className="px-3 py-1 rounded-full bg-amber-500 text-white text-xs font-bold hover:bg-amber-600">
                                Tandai Lunas
                              </button>
                          }
                        </div>
                      </div>
                    ))}
                  </div>
                </div>
              )}
            </Card>
          );
        })}
      </div>
    </div>
  );
}

/* ═══════════════════════════════════════════════
   INVOICE PDF EXPORT (shared by Admin + Client Overview)
   Usage: window.exportInvoiceDoc(inv, clientName)
   Throws on jsPDF missing — caller handles toast.
   ═══════════════════════════════════════════════ */
function exportInvoiceDoc(inv, clientName = "—") {
  const jspdfNs = window.jspdf;
  if (!jspdfNs || !jspdfNs.jsPDF) throw new Error("jsPDF belum termuat (cek koneksi CDN).");
  const doc = new jspdfNs.jsPDF({ unit: "mm", format: "a4" });
  const co = window.COMPANY_SETTINGS || {};

  const sep = " · ";
  const sepIdx = (inv.period || "").indexOf(sep);
  const itemName  = sepIdx > 0 ? inv.period.slice(0, sepIdx) : (inv.period || "—");
  const periodSub = sepIdx > 0 ? inv.period.slice(sepIdx + sep.length) : "";

  const qty       = Number(inv.qty)       || 1;
  const unitPrice = Number(inv.unitPrice) || Number(inv.amount) || 0;

  doc.setFillColor(255, 45, 85);
  doc.rect(0, 0, 210, 4, "F");

  doc.setTextColor(255, 45, 85);
  doc.setFont("helvetica", "bold"); doc.setFontSize(26);
  doc.text("INVOICE", 14, 20);

  let logoDrawn = false;
  if (co.logo_url) {
    const tryFmt = (fmt) => { try { doc.addImage(co.logo_url, fmt, 150, 10, 40, 40); return true; } catch { return false; } };
    logoDrawn = tryFmt("PNG") || tryFmt("JPEG") || tryFmt("WEBP");
  }

  let y = 30;
  doc.setTextColor(20);
  doc.setFont("helvetica", "bold"); doc.setFontSize(12);
  if (co.name) { doc.text(co.name, 14, y, { maxWidth: 130 }); y += 5; }
  doc.setFont("helvetica", "normal"); doc.setFontSize(9); doc.setTextColor(110);
  if (co.tagline)    { doc.text(co.tagline,    14, y, { maxWidth: 130 }); y += 4; }
  if (co.legal_name) { doc.text(co.legal_name, 14, y, { maxWidth: 130 }); y += 4; }
  y += 1;
  if (co.address) {
    doc.splitTextToSize(co.address, 130).forEach(line => { doc.text(line, 14, y); y += 4; });
  }
  const contactParts = [co.phone && `Telp: ${co.phone}`, co.email, co.website].filter(Boolean);
  if (contactParts.length) {
    doc.splitTextToSize(contactParts.join(" · "), 130).forEach(line => { doc.text(line, 14, y); y += 4; });
  }
  if (co.npwp) { doc.text(`NPWP: ${co.npwp}`, 14, y, { maxWidth: 130 }); y += 4; }

  const headerEndY = Math.max(y + 4, logoDrawn ? 56 : y + 4);
  doc.setDrawColor(220);
  doc.line(14, headerEndY, 196, headerEndY);

  const billY = headerEndY + 8;
  doc.setTextColor(20);
  doc.setFont("helvetica", "bold"); doc.setFontSize(10);
  doc.text("Ditagihkan kepada:", 14, billY);
  doc.setFont("helvetica", "normal");
  doc.text(clientName, 14, billY + 6, { maxWidth: 110 });
  if (inv.machineId) doc.text(`Mesin: ${inv.machineId}`, 14, billY + 12);

  doc.setFont("helvetica", "bold"); doc.setFontSize(10);
  doc.text(`No: ${inv.id}`, 196, billY, { align: "right" });
  doc.setFont("helvetica", "normal"); doc.setFontSize(9);
  doc.text(`Tanggal: ${formatDateID(inv.date)}`, 196, billY + 6, { align: "right" });
  doc.setFont("helvetica", "bold");
  doc.text(`Status: ${inv.status}`, 196, billY + 12, { align: "right" });

  const tableTop = billY + 22;
  doc.setFillColor(245, 245, 244);
  doc.rect(14, tableTop, 182, 9, "F");
  doc.setFont("helvetica", "bold"); doc.setFontSize(10); doc.setTextColor(20);
  const X_DESC = 18, X_QTY = 120, X_UNIT = 160, X_TOTAL = 192;
  doc.text("Deskripsi",     X_DESC,  tableTop + 6);
  doc.text("Qty",           X_QTY,   tableTop + 6, { align: "right" });
  doc.text("Harga Satuan",  X_UNIT,  tableTop + 6, { align: "right" });
  doc.text("Jumlah",        X_TOTAL, tableTop + 6, { align: "right" });

  let rowY = tableTop + 16;
  doc.setFont("helvetica", "normal"); doc.setFontSize(10);
  doc.text(itemName, X_DESC, rowY, { maxWidth: 95 });
  doc.text(`${qty} bulan`,        X_QTY,   rowY, { align: "right" });
  doc.text(formatRp(unitPrice),   X_UNIT,  rowY, { align: "right" });
  doc.text(formatRp(inv.amount),  X_TOTAL, rowY, { align: "right" });
  if (periodSub) {
    doc.setFont("helvetica", "italic"); doc.setFontSize(8); doc.setTextColor(120);
    doc.text(periodSub, X_DESC, rowY + 5, { maxWidth: 95 });
    rowY += 5;
  }

  const totalY = rowY + 12;
  doc.setDrawColor(60);
  doc.line(14, totalY - 5, 196, totalY - 5);
  doc.setFont("helvetica", "bold"); doc.setFontSize(13); doc.setTextColor(20);
  doc.text("TOTAL", X_DESC, totalY);
  doc.setTextColor(255, 45, 85);
  doc.text(formatRp(inv.amount), X_TOTAL, totalY, { align: "right" });

  let footY = totalY + 14;
  doc.setDrawColor(220);
  doc.line(14, footY - 5, 196, footY - 5);

  if (co.bank_name || co.bank_account_number) {
    doc.setFont("helvetica", "bold"); doc.setFontSize(9); doc.setTextColor(20);
    doc.text("Pembayaran via transfer:", 14, footY); footY += 5;
    doc.setFont("helvetica", "normal"); doc.setTextColor(60);
    const bankParts = [
      co.bank_name && (co.bank_branch ? `${co.bank_name} · ${co.bank_branch}` : co.bank_name),
      co.bank_account_number && `Rek: ${co.bank_account_number}`,
      co.bank_account_name   && `a.n. ${co.bank_account_name}`,
    ].filter(Boolean);
    if (bankParts.length) {
      doc.splitTextToSize(bankParts.join("  ·  "), 180).forEach(line => { doc.text(line, 14, footY); footY += 4; });
    }
    footY += 2;
  }

  if (co.invoice_notes) {
    doc.setFont("helvetica", "italic"); doc.setFontSize(8); doc.setTextColor(100);
    doc.splitTextToSize(co.invoice_notes, 180).forEach(line => { doc.text(line, 14, footY); footY += 4; });
  }

  doc.setFont("helvetica", "normal"); doc.setFontSize(9); doc.setTextColor(120);
  doc.text(`Metode pembayaran: ${inv.method || "—"}`, 14, 275);
  if (co.invoice_footer) {
    doc.setFont("helvetica", "italic");
    doc.text(co.invoice_footer, 14, 285, { maxWidth: 180 });
  }

  doc.save(`${inv.id}.pdf`);
}

/* ═══════════════════════════════════════════════
   ADMIN: INVOICE
   ═══════════════════════════════════════════════ */
const INVOICE_STATUSES = ["Lunas", "Outstanding", "Pending"];
const INVOICE_METHODS  = ["Transfer","QRIS","BCA VA","Mandiri VA","BNI VA","BRI VA","GoPay","OVO","DANA","Tunai"];

function statusTone(s) {
  if (s === "Lunas") return "success";
  if (s === "Outstanding") return "danger";
  return "warning";
}

function monthsBetween(start, end) {
  if (!start || !end) return 0;
  const s = new Date(start), e = new Date(end);
  if (isNaN(s) || isNaN(e) || e < s) return 0;
  return (e.getFullYear() - s.getFullYear()) * 12 + (e.getMonth() - s.getMonth()) + 1;
}

const EMPTY_INV_FORM = {
  clientId: "", machineId: "", item: "Sewa Cloud",
  periodStart: "", periodEnd: "",
  qty: "1", unitPrice: "", manualAmount: false, amount: "",
  status: "Outstanding", method: "Transfer",
};

function AdminInvoicesView() {
  const { invoices, setInvoices, allMachines, users, toast } = useApp();
  const [filter, setFilter]             = useStateAdmin("all");
  const [search, setSearch]             = useStateAdmin("");
  const [clientFilter, setClientFilter] = useStateAdmin("all");
  const [showNew, setShowNew]           = useStateAdmin(false);
  const [newInv, setNewInv]             = useStateAdmin(EMPTY_INV_FORM);

  const clients = users.filter(u => u.role === "client");
  const getClientName = (cid) => users.find(u => u.id === cid)?.name || "—";

  // Auto-derive bulan dari periode (hint untuk auto-fill qty), dan amount = qty × unitPrice
  const computedMonths = useMemoAdmin(
    () => monthsBetween(newInv.periodStart, newInv.periodEnd),
    [newInv.periodStart, newInv.periodEnd]
  );
  const computedAmount = useMemoAdmin(
    () => (Number(newInv.qty || 0) * Number(newInv.unitPrice || 0)),
    [newInv.qty, newInv.unitPrice]
  );
  const effectiveAmount = newInv.manualAmount ? Number(newInv.amount || 0) : computedAmount;

  const filtered = useMemoAdmin(() => {
    let list = invoices;
    if (filter !== "all") {
      const want = filter[0].toUpperCase() + filter.slice(1);
      list = list.filter(i => i.status === want);
    }
    if (clientFilter !== "all") list = list.filter(i => i.clientId === clientFilter);
    if (search) {
      const q = search.toLowerCase();
      list = list.filter(i =>
        i.id.toLowerCase().includes(q) ||
        (i.machineId || "").toLowerCase().includes(q) ||
        (i.period   || "").toLowerCase().includes(q) ||
        getClientName(i.clientId).toLowerCase().includes(q)
      );
    }
    return [...list].sort((a, b) => new Date(b.date) - new Date(a.date));
  }, [invoices, filter, clientFilter, search, users]);

  const totalFiltered = filtered.reduce((s, i) => s + i.amount, 0);

  function markPaid(id) {
    const target = invoices.find(i => i.id === id);
    if (!target) return;
    const updated = { ...target, status: "Lunas" };
    setInvoices(prev => prev.map(i => i.id === id ? updated : i));
    toast("Invoice ditandai Lunas.", "success");
    db.upsertInvoice(updated).catch(err => toast("Gagal simpan ke Supabase: " + err.message, "danger"));
  }

  function addInvoice(e) {
    e.preventDefault();
    if (!newInv.clientId)   { toast("Pilih client.", "danger"); return; }
    if (!newInv.item.trim()){ toast("Isi item / deskripsi.", "danger"); return; }
    if (!newInv.periodStart || !newInv.periodEnd) { toast("Pilih periode (dari–sampai).", "danger"); return; }
    if (new Date(newInv.periodEnd) < new Date(newInv.periodStart)) {
      toast("Tanggal akhir periode lebih awal dari tanggal mulai.", "danger"); return;
    }
    if (effectiveAmount <= 0) { toast("Nominal invalid (cek harga/bulan atau input manual).", "danger"); return; }

    const periodText = `${newInv.item.trim()} · ${formatDateID(newInv.periodStart)} – ${formatDateID(newInv.periodEnd)}`;
    const id = "INV-" + Date.now();
    const qty       = Number(newInv.qty) || 1;
    const unitPrice = newInv.manualAmount
      ? Math.round(Number(effectiveAmount) / qty)   // derive unit price from manual total
      : Number(newInv.unitPrice) || 0;
    const created = {
      id,
      clientId:  newInv.clientId,
      machineId: newInv.machineId || null,
      amount:    Number(effectiveAmount),
      date:      newInv.periodStart, // invoice date = awal periode
      period:    periodText,
      method:    newInv.method,
      status:    newInv.status,
      qty,
      unitPrice,
    };
    setInvoices(prev => [...prev, created]);
    setNewInv(EMPTY_INV_FORM);
    setShowNew(false);
    toast(`Invoice ${id} dibuat (${formatRp(created.amount)}).`, "success");
    db.upsertInvoice(created).catch(err => toast("Gagal simpan ke Supabase: " + err.message, "danger"));
  }

  function exportInvoicePDF(inv) {
    try { exportInvoiceDoc(inv, getClientName(inv.clientId)); }
    catch (e) { toast(e.message || "Gagal membuat PDF.", "danger"); }
  }

  return (
    <div className="px-5 md:px-8 py-7 md:py-9 max-w-6xl mx-auto">
      <PageHeader eyebrow="Admin" jp="請求書" title="Invoice"
        sub={`${invoices.length} invoice · Total tampil: ${formatRp(totalFiltered)}`}
        actions={
          <Button onClick={() => setShowNew(true)} variant="primary">
            <Icon name="plus" size={16}/> Buat Invoice
          </Button>
        }
      />

      {/* Filters */}
      <div className="flex flex-wrap items-center gap-3 mb-5">
        <div className="relative">
          <Icon name="search" size={15} className="absolute left-3 top-1/2 -translate-y-1/2 text-stone-400"/>
          <input type="text" value={search} onChange={e => setSearch(e.target.value)}
            placeholder="Cari invoice / client / mesin..."
            className="pl-8 pr-4 py-2 rounded-xl border border-stone-300 bg-white text-sm focus:border-[#FF2D55] outline-none"/>
        </div>
        <select value={clientFilter} onChange={e => setClientFilter(e.target.value)}
          className="px-3 py-2 rounded-xl border border-stone-300 bg-white text-sm focus:border-[#FF2D55] outline-none">
          <option value="all">Semua client</option>
          {clients.map(c => <option key={c.id} value={c.id}>{c.name}</option>)}
        </select>
        {[
          { id:"all", label:"Semua" },
          { id:"lunas", label:"Lunas" },
          { id:"outstanding", label:"Outstanding" },
          { id:"pending", label:"Pending" },
        ].map(f => (
          <button key={f.id} onClick={() => setFilter(f.id)}
            className={`px-4 py-2 rounded-full text-sm font-semibold transition ${filter === f.id ? "bg-[#1A1A1A] text-white" : "bg-white border border-stone-200 text-stone-700 hover:border-[#FF2D55] hover:text-[#FF2D55]"}`}>
            {f.label}
          </button>
        ))}
      </div>

      {/* Table */}
      <Card className="overflow-hidden">
        <div className="overflow-x-auto">
          <table className="w-full text-sm">
            <thead>
              <tr className="bg-stone-50 border-b border-stone-200 text-[11px] font-bold uppercase tracking-widest text-stone-500">
                <th className="px-5 py-3 text-left">Invoice ID</th>
                <th className="px-5 py-3 text-left hidden md:table-cell">Client</th>
                <th className="px-5 py-3 text-left hidden lg:table-cell">Mesin</th>
                <th className="px-5 py-3 text-left hidden md:table-cell">Periode</th>
                <th className="px-5 py-3 text-left hidden lg:table-cell">Metode</th>
                <th className="px-5 py-3 text-right">Nominal</th>
                <th className="px-5 py-3 text-center">Status</th>
                <th className="px-5 py-3 text-right">Aksi</th>
              </tr>
            </thead>
            <tbody>
              {filtered.map(inv => (
                <tr key={inv.id} className="border-b border-stone-100 last:border-0 hover:bg-stone-50/50">
                  <td className="px-5 py-4">
                    <div className="font-mono text-xs text-[#1A1A1A] font-semibold">{inv.id}</div>
                    <div className="text-[11px] text-stone-400 mt-0.5">{formatDateID(inv.date)}</div>
                  </td>
                  <td className="px-5 py-4 hidden md:table-cell text-stone-700">{getClientName(inv.clientId)}</td>
                  <td className="px-5 py-4 hidden lg:table-cell">
                    {inv.machineId
                      ? <span className="font-mono text-xs bg-stone-100 px-2 py-1 rounded">{inv.machineId}</span>
                      : <span className="text-xs text-stone-400 italic">—</span>}
                  </td>
                  <td className="px-5 py-4 hidden md:table-cell text-stone-600">{inv.period}</td>
                  <td className="px-5 py-4 hidden lg:table-cell text-stone-600">{inv.method}</td>
                  <td className="px-5 py-4 text-right font-semibold text-[#1A1A1A]">{formatRp(inv.amount)}</td>
                  <td className="px-5 py-4 text-center">
                    <Badge tone={statusTone(inv.status)}>{inv.status}</Badge>
                  </td>
                  <td className="px-5 py-4">
                    <div className="flex items-center justify-end gap-1">
                      <button className="p-2 rounded-lg text-stone-400 hover:bg-stone-100 hover:text-[#FF2D55]"
                        onClick={() => toast(`Invoice ${inv.id} — ${formatRp(inv.amount)} · ${inv.status}`, "info")}>
                        <Icon name="eye" size={15}/>
                      </button>
                      <button title="Download PDF" onClick={() => exportInvoicePDF(inv)}
                        className="p-2 rounded-lg text-stone-400 hover:bg-stone-100 hover:text-[#FF2D55]">
                        <Icon name="download" size={15}/>
                      </button>
                      {inv.status !== "Lunas" && (
                        <button onClick={() => markPaid(inv.id)} title="Tandai Lunas"
                          className="p-2 rounded-lg text-stone-400 hover:bg-emerald-50 hover:text-emerald-700">
                          <Icon name="check" size={15}/>
                        </button>
                      )}
                    </div>
                  </td>
                </tr>
              ))}
              {filtered.length === 0 && (
                <tr><td colSpan={8} className="px-5 py-10 text-center text-stone-400 text-sm">Tidak ada invoice ditemukan.</td></tr>
              )}
            </tbody>
          </table>
        </div>
        {/* Footer total */}
        <div className="px-5 py-4 border-t border-stone-200 bg-stone-50 flex justify-between items-center">
          <span className="text-sm text-stone-500">{filtered.length} invoice</span>
          <div className="font-display text-lg text-[#FF2D55]">{formatRp(totalFiltered)}</div>
        </div>
      </Card>

      {/* New Invoice Modal */}
      <Modal open={showNew} onClose={() => setShowNew(false)} title="Buat Invoice Baru" width="max-w-2xl">
        <form onSubmit={addInvoice} className="space-y-4">
          <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
            {/* Client */}
            <div>
              <label className="text-[11px] font-bold uppercase tracking-widest text-stone-500">Client *</label>
              <select value={newInv.clientId}
                onChange={e => setNewInv({...newInv, clientId: e.target.value, machineId: ""})}
                className="mt-1.5 w-full px-4 py-2.5 rounded-xl border border-stone-300 bg-white focus:border-[#FF2D55] outline-none text-sm">
                <option value="">Pilih client...</option>
                {clients.map(c => <option key={c.id} value={c.id}>{c.name}</option>)}
              </select>
            </div>

            {/* Mesin (opsional) */}
            <div>
              <label className="text-[11px] font-bold uppercase tracking-widest text-stone-500">
                Mesin <span className="text-stone-400 font-normal normal-case tracking-normal">(opsional — kosongkan untuk Cloud / non-mesin)</span>
              </label>
              <select value={newInv.machineId} onChange={e => setNewInv({...newInv, machineId: e.target.value})}
                className="mt-1.5 w-full px-4 py-2.5 rounded-xl border border-stone-300 bg-white focus:border-[#FF2D55] outline-none text-sm">
                <option value="">— Tidak terkait mesin —</option>
                {allMachines.filter(m => !newInv.clientId || m.clientId === newInv.clientId).map(m => (
                  <option key={m.id} value={m.id}>{m.id} — {m.model}</option>
                ))}
              </select>
            </div>

            {/* Item / deskripsi */}
            <Field label="Item / Deskripsi *" value={newInv.item}
              onChange={v => setNewInv({...newInv, item: v})}
              placeholder="cth: Sewa Cloud, Sewa Mesin, Refill, …" full required/>

            {/* Periode */}
            <Field label="Periode Dari *" type="date" value={newInv.periodStart}
              onChange={v => setNewInv({...newInv, periodStart: v})} required/>
            <Field label="Periode Sampai *" type="date" value={newInv.periodEnd}
              onChange={v => setNewInv({...newInv, periodEnd: v})} required/>

            {/* Qty (bulan) */}
            <div>
              <label className="text-[11px] font-bold uppercase tracking-widest text-stone-500">Qty (Bulan) *</label>
              <input type="number" min="1" value={newInv.qty}
                onChange={e => setNewInv({...newInv, qty: e.target.value})}
                className="mt-1.5 w-full px-4 py-2.5 rounded-xl border border-stone-300 bg-white text-[#1A1A1A] focus:border-[#FF2D55] outline-none text-sm"/>
              {computedMonths > 0 && Number(newInv.qty) !== computedMonths && (
                <button type="button"
                  onClick={() => setNewInv({...newInv, qty: String(computedMonths)})}
                  className="mt-1 text-[11px] text-[#FF2D55] hover:underline">
                  Auto-isi {computedMonths} (berdasarkan periode tanggal) →
                </button>
              )}
            </div>

            {/* Harga Satuan */}
            <Field label="Harga Satuan (Rp/Bulan) *" type="number" value={newInv.unitPrice}
              onChange={v => setNewInv({...newInv, unitPrice: v})}
              placeholder="cth: 350000"/>

            {/* Nominal total */}
            <div className="md:col-span-2">
              <label className="text-[11px] font-bold uppercase tracking-widest text-stone-500 flex items-center justify-between">
                <span>Nominal Total (Rp)</span>
                <label className="flex items-center gap-1.5 normal-case tracking-normal font-normal text-stone-500 cursor-pointer">
                  <input type="checkbox" checked={newInv.manualAmount}
                    onChange={e => setNewInv({...newInv, manualAmount: e.target.checked})}/>
                  Override manual
                </label>
              </label>
              <input type="number"
                value={newInv.manualAmount ? newInv.amount : computedAmount || ""}
                onChange={e => setNewInv({...newInv, amount: e.target.value})}
                disabled={!newInv.manualAmount}
                className={`mt-1.5 w-full px-4 py-2.5 rounded-xl border border-stone-300 text-[#1A1A1A] focus:border-[#FF2D55] outline-none text-sm ${newInv.manualAmount ? "bg-white" : "bg-stone-50 text-stone-500"}`}/>
              {!newInv.manualAmount && Number(newInv.qty) > 0 && Number(newInv.unitPrice) > 0 && (
                <div className="mt-1.5 text-[11px] text-stone-500">
                  {newInv.qty} bulan × {formatRp(Number(newInv.unitPrice))} = <span className="font-semibold text-[#FF2D55]">{formatRp(computedAmount)}</span>
                </div>
              )}
            </div>

            {/* Status */}
            <div>
              <label className="text-[11px] font-bold uppercase tracking-widest text-stone-500">Status *</label>
              <select value={newInv.status} onChange={e => setNewInv({...newInv, status: e.target.value})}
                className="mt-1.5 w-full px-4 py-2.5 rounded-xl border border-stone-300 bg-white focus:border-[#FF2D55] outline-none text-sm">
                {INVOICE_STATUSES.map(s => <option key={s}>{s}</option>)}
              </select>
            </div>

            {/* Metode */}
            <div>
              <label className="text-[11px] font-bold uppercase tracking-widest text-stone-500">Metode Pembayaran</label>
              <select value={newInv.method} onChange={e => setNewInv({...newInv, method: e.target.value})}
                className="mt-1.5 w-full px-4 py-2.5 rounded-xl border border-stone-300 bg-white focus:border-[#FF2D55] outline-none text-sm">
                {INVOICE_METHODS.map(m => <option key={m}>{m}</option>)}
              </select>
            </div>
          </div>

          <div className="flex gap-2 pt-2">
            <Button type="submit" variant="primary">Buat Invoice</Button>
            <Button type="button" variant="subtle" onClick={() => setShowNew(false)}>Batal</Button>
          </div>
        </form>
      </Modal>
    </div>
  );
}

/* ═══════════════════════════════════════════════
   ADMIN: PENGATURAN PERUSAHAAN
   ═══════════════════════════════════════════════ */
const SETTINGS_TABS = [
  { id: "company",  label: "Perusahaan", icon: "shield"  },
  { id: "contact",  label: "Kontak",     icon: "user"    },
  { id: "bank",     label: "Rekening",   icon: "wallet"  },
  { id: "invoice",  label: "Invoice",    icon: "receipt" },
];

function SettingsField({ label, type = "text", value, onChange, placeholder, hint, full }) {
  return (
    <div className={full ? "md:col-span-2" : ""}>
      <label className="text-[11px] font-bold uppercase tracking-widest text-stone-500">{label}</label>
      {type === "textarea" ? (
        <textarea value={value || ""} onChange={e => onChange(e.target.value)} placeholder={placeholder} rows={3}
          className="mt-1.5 w-full px-4 py-2.5 rounded-xl border border-stone-300 bg-white text-[#1A1A1A] focus:border-[#FF2D55] focus:ring-2 focus:ring-pink-100 outline-none transition resize-none text-sm"/>
      ) : (
        <input type={type} value={value || ""} onChange={e => onChange(e.target.value)} placeholder={placeholder}
          className="mt-1.5 w-full px-4 py-2.5 rounded-xl border border-stone-300 bg-white text-[#1A1A1A] focus:border-[#FF2D55] focus:ring-2 focus:ring-pink-100 outline-none transition text-sm"/>
      )}
      {hint && <div className="mt-1 text-[11px] text-stone-400">{hint}</div>}
    </div>
  );
}

function AdminSettingsView() {
  const { toast } = useApp();
  const [tab, setTab]           = useStateAdmin("company");
  const [form, setForm]         = useStateAdmin(() => ({ ...COMPANY_DEFAULTS, ...(window.COMPANY_SETTINGS || {}) }));
  const [saving, setSaving]     = useStateAdmin(false);
  const [dirty, setDirty]       = useStateAdmin(false);

  const set = (k, v) => { setForm(prev => ({ ...prev, [k]: v })); setDirty(true); };

  async function handleLogoUpload(e) {
    const file = e.target.files?.[0];
    if (!file) return;
    if (file.size > 500 * 1024) { toast("Logo maks 500 KB (disimpan sebagai base64).", "warning"); return; }
    const reader = new FileReader();
    reader.onload = () => { set("logo_url", reader.result); toast("Logo dimuat — klik Simpan untuk persist.", "info"); };
    reader.onerror = () => toast("Gagal baca file.", "danger");
    reader.readAsDataURL(file);
  }

  async function save() {
    setSaving(true);
    try {
      await db.updateSettings("company", form);
      setDirty(false);
      toast("Pengaturan perusahaan tersimpan.", "success");
    } catch (err) {
      toast("Gagal simpan: " + err.message, "danger");
    } finally {
      setSaving(false);
    }
  }

  return (
    <div className="px-5 md:px-8 py-7 md:py-9 max-w-5xl mx-auto">
      <PageHeader eyebrow="Admin" jp="会社設定" title="Pengaturan Perusahaan"
        sub="Data ini muncul di invoice PDF, header dashboard, dan komunikasi resmi."
        actions={
          <Button onClick={save} variant="primary" disabled={saving || !dirty}>
            <Icon name={saving ? "refresh" : "check"} size={16}/> {saving ? "Menyimpan..." : "Simpan"}
          </Button>
        }
      />

      {/* Tabs */}
      <div className="flex flex-wrap gap-2 mb-5 border-b border-stone-200">
        {SETTINGS_TABS.map(t => (
          <button key={t.id} onClick={() => setTab(t.id)}
            className={`px-4 py-2.5 -mb-px border-b-2 text-sm font-semibold transition flex items-center gap-2 ${
              tab === t.id
                ? "border-[#FF2D55] text-[#FF2D55]"
                : "border-transparent text-stone-500 hover:text-[#1A1A1A]"
            }`}>
            <Icon name={t.icon} size={15}/> {t.label}
          </button>
        ))}
      </div>

      {/* TAB 1 — Perusahaan */}
      {tab === "company" && (
        <Card className="p-6">
          <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
            <SettingsField label="Nama Brand" value={form.name} onChange={v => set("name", v)} placeholder="Yappari! Vending Machine"/>
            <SettingsField label="Nama Legal (PT)" value={form.legal_name} onChange={v => set("legal_name", v)} placeholder="PT. Indie Kreasi Group"/>
            <SettingsField label="Tagline" value={form.tagline} onChange={v => set("tagline", v)} full placeholder="Solusi Vending Machine Modern"/>
            <SettingsField label="Logo URL" value={form.logo_url} onChange={v => set("logo_url", v)} full hint="Boleh URL eksternal, atau upload file di bawah (disimpan sebagai data: URL)"/>

            <div className="md:col-span-2 flex items-start gap-4 p-4 rounded-xl bg-stone-50 border border-stone-200">
              <div className="w-24 h-24 rounded-xl bg-white border border-stone-200 flex items-center justify-center overflow-hidden shrink-0">
                {form.logo_url
                  ? <img src={form.logo_url} alt="logo" className="max-w-full max-h-full object-contain"/>
                  : <span className="text-[10px] font-bold uppercase tracking-widest text-stone-300">No Logo</span>}
              </div>
              <div className="flex-1">
                <div className="text-xs font-bold uppercase tracking-widest text-stone-500 mb-2">Preview Logo</div>
                <input type="file" accept="image/*" onChange={handleLogoUpload}
                  className="text-xs file:mr-3 file:px-3 file:py-1.5 file:rounded-full file:border-0 file:bg-[#FF2D55] file:text-white file:font-semibold file:cursor-pointer hover:file:bg-[#E61243]"/>
                <div className="mt-1 text-[11px] text-stone-400">PNG/JPG/SVG, maks 500 KB. Untuk file lebih besar pakai URL eksternal.</div>
                {form.logo_url && (
                  <button onClick={() => set("logo_url", "")} className="mt-2 text-[11px] text-rose-600 hover:underline">Hapus logo</button>
                )}
              </div>
            </div>
          </div>
        </Card>
      )}

      {/* TAB 2 — Kontak */}
      {tab === "contact" && (
        <Card className="p-6">
          <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
            <SettingsField label="Nomor Telepon" value={form.phone} onChange={v => set("phone", v)} placeholder="0822 1034 6828"/>
            <SettingsField label="WhatsApp (format intl)" value={form.whatsapp} onChange={v => set("whatsapp", v)} placeholder="628220346828" hint="Tanpa tanda + atau spasi"/>
            <SettingsField label="Email" type="email" value={form.email} onChange={v => set("email", v)} placeholder="hello@yappari.id"/>
            <SettingsField label="Website" value={form.website} onChange={v => set("website", v)} placeholder="yappari.id"/>
            <SettingsField label="Alamat Lengkap" type="textarea" value={form.address} onChange={v => set("address", v)} full placeholder="Ruko Tematik Paramount Serpong..."/>
          </div>
        </Card>
      )}

      {/* TAB 3 — Bank */}
      {tab === "bank" && (
        <Card className="p-6">
          <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
            <SettingsField label="Nama Bank" value={form.bank_name} onChange={v => set("bank_name", v)} placeholder="BCA"/>
            <SettingsField label="Cabang" value={form.bank_branch} onChange={v => set("bank_branch", v)} placeholder="KCP Gading Serpong"/>
            <SettingsField label="Nomor Rekening" value={form.bank_account_number} onChange={v => set("bank_account_number", v)} placeholder="1234567890"/>
            <SettingsField label="Nama Pemilik Rekening" value={form.bank_account_name} onChange={v => set("bank_account_name", v)} placeholder="PT. Indie Kreasi Group"/>
            <SettingsField label="NPWP" value={form.npwp} onChange={v => set("npwp", v)} full placeholder="00.000.000.0-000.000"/>
          </div>
        </Card>
      )}

      {/* TAB 4 — Invoice */}
      {tab === "invoice" && (
        <div className="grid grid-cols-1 lg:grid-cols-2 gap-5">
          <Card className="p-6">
            <SettingsField label="Catatan Default Invoice" type="textarea" value={form.invoice_notes} onChange={v => set("invoice_notes", v)} full placeholder="Pembayaran dapat dilakukan via transfer bank atau QRIS."/>
            <div className="mt-4">
              <SettingsField label="Footer Invoice" type="textarea" value={form.invoice_footer} onChange={v => set("invoice_footer", v)} full placeholder="Terima kasih atas kepercayaan Anda kepada Yappari!"/>
            </div>
          </Card>

          {/* Preview mockup */}
          <Card className="p-6 bg-stone-50">
            <div className="text-[11px] font-bold uppercase tracking-widest text-stone-500 mb-3">Preview Invoice</div>
            <div className="bg-white rounded-xl border border-stone-200 p-5 text-xs space-y-3 shadow-sm">
              <div className="bg-[#FF2D55] text-white -mx-5 -mt-5 px-5 py-3 rounded-t-xl flex justify-between items-center">
                <span className="font-display text-lg">INVOICE</span>
                <div className="text-right text-[10px]">
                  <div className="font-bold">{form.name || "—"}</div>
                  {form.tagline && <div className="opacity-80">{form.tagline}</div>}
                  {form.legal_name && <div className="opacity-80">{form.legal_name}</div>}
                </div>
              </div>
              <div className="text-stone-500 text-[10px] leading-relaxed">
                {form.address && <div>{form.address}</div>}
                <div>{[form.phone && `Telp: ${form.phone}`, form.email, form.website].filter(Boolean).join("  ·  ")}</div>
                {form.npwp && <div>NPWP: {form.npwp}</div>}
              </div>
              <div className="border-t border-b border-stone-200 py-2 flex justify-between">
                <span className="font-bold">Sample Item</span>
                <span className="font-bold">Rp 2.100.000</span>
              </div>
              {(form.bank_name || form.bank_account_number) && (
                <div className="text-[10px] text-stone-600">
                  <div className="font-bold mb-0.5">Pembayaran via transfer:</div>
                  {form.bank_name && <div>Bank: {form.bank_name}{form.bank_branch && " · " + form.bank_branch}</div>}
                  {form.bank_account_number && <div>No. Rek: {form.bank_account_number}</div>}
                  {form.bank_account_name && <div>Atas nama: {form.bank_account_name}</div>}
                </div>
              )}
              {form.invoice_notes && <div className="text-[10px] text-stone-500 italic">{form.invoice_notes}</div>}
              {form.invoice_footer && <div className="text-[10px] text-stone-400 pt-2 border-t border-stone-100">{form.invoice_footer}</div>}
            </div>
          </Card>
        </div>
      )}

      {dirty && (
        <div className="mt-5 px-4 py-3 rounded-xl bg-amber-50 border border-amber-200 text-amber-800 text-sm flex items-center gap-2">
          <Icon name="info" size={15}/> Ada perubahan yang belum disimpan. Klik <strong>Simpan</strong> di pojok kanan atas.
        </div>
      )}
    </div>
  );
}

Object.assign(window, { AdminClientsView, AdminMachinesView, AdminBillingView, AdminInvoicesView, AdminSettingsView, exportInvoiceDoc });
