// ============================================================
// IPS EXPENSE TRACKER — Simple File-Only Mode
// No AI extraction. Receipts auto-file to monthly folders.
// ============================================================

const FIREBASE_CONFIG = {
  apiKey: "AIzaSyBPo2PAEEGuEAcVqphvMK1wuXTcai03PPM",
  authDomain: "ipsexpense.firebaseapp.com",
  projectId: "ipsexpense",
  storageBucket: "ipsexpense.firebasestorage.app",
  messagingSenderId: "370910103560",
  appId: "1:370910103560:web:017de72c0252ff044e69bd"
};

// ============================================================
firebase.initializeApp(FIREBASE_CONFIG);
const db = firebase.firestore();
const storage = firebase.storage();

const { useState, useEffect, useRef } = React;

const MONTHS = ["January","February","March","April","May","June","July","August","September","October","November","December"];
const MENU_PIN = "8522";

// ─── Helpers ─────────────────────────────────────────────────
function readFileAsBase64(file) {
  return new Promise((res, rej) => {
    const r = new FileReader();
    r.onload = () => res(r.result.split(",")[1]);
    r.onerror = rej;
    r.readAsDataURL(file);
  });
}
function readFileAsDataURL(file) {
  return new Promise((res, rej) => {
    const r = new FileReader();
    r.onload = () => res(r.result);
    r.onerror = rej;
    r.readAsDataURL(file);
  });
}
function fmtMoney(n) {
  if (n == null || n === "") return "";
  return parseFloat(n).toLocaleString("en-US", { style: "currency", currency: "USD" });
}

// ─── Firebase: Cards ──────────────────────────────────────────
async function loadCards() {
  const snap = await db.collection("cards").orderBy("createdAt").get();
  return snap.docs.map(d => ({ id: d.id, ...d.data() }));
}
async function createCard(name) {
  const ref = await db.collection("cards").add({ name, createdAt: firebase.firestore.FieldValue.serverTimestamp() });
  return ref.id;
}
async function deleteCard(id) {
  await db.collection("cards").doc(id).delete();
}

// ─── Firebase: Receipts ───────────────────────────────────────
async function saveReceipt({ cardId, cardName, year, month, fileBase64, fileName, mimeType }) {
  const monthStr = String(month + 1).padStart(2, "0");
  const ext = (fileName || "jpg").split(".").pop();
  const storageFileName = Date.now() + "." + ext;
  const storagePath = "receipts/" + cardId + "/" + year + "/" + monthStr + "_" + MONTHS[month] + "/" + storageFileName;
  const ref = storage.ref(storagePath);
  const bytes = atob(fileBase64);
  const ab = new ArrayBuffer(bytes.length);
  const ia = new Uint8Array(ab);
  for (let i = 0; i < bytes.length; i++) ia[i] = bytes.charCodeAt(i);
  await ref.put(new Blob([ab], { type: mimeType }));
  const downloadUrl = await ref.getDownloadURL();
  const docRef = await db.collection("receipts").add({
    cardId, cardName, year, month,
    storagePath, downloadUrl, mimeType, fileName: storageFileName,
    createdAt: firebase.firestore.FieldValue.serverTimestamp()
  });
  return { id: docRef.id, downloadUrl };
}

async function loadReceipts(cardId, year, month) {
  const snap = await db.collection("receipts")
    .where("cardId", "==", cardId)
    .where("year", "==", year)
    .where("month", "==", month)
    .get();
  const docs = snap.docs.map(d => ({ id: d.id, ...d.data() }));
  return docs.sort((a, b) => {
    const ta = a.createdAt ? a.createdAt.toMillis() : 0;
    const tb = b.createdAt ? b.createdAt.toMillis() : 0;
    return tb - ta;
  });
}

async function deleteReceipt(receipt) {
  await db.collection("receipts").doc(receipt.id).delete();
  try { await storage.ref(receipt.storagePath).delete(); } catch (e) {}
}

// ─── Styles ───────────────────────────────────────────────────
const gold = "#c8a96e";
const S = {
  app: { fontFamily: "'DM Sans', sans-serif", background: "#0f0f0f", minHeight: "100vh", color: "#f0ece4", maxWidth: 480, margin: "0 auto" },
  header: { padding: "52px 24px 20px", borderBottom: "1px solid #1e1e1e" },
  mono: { fontFamily: "'DM Mono', monospace" },
  label: { fontFamily: "'DM Mono', monospace", fontSize: 11, letterSpacing: "0.15em", textTransform: "uppercase", color: "#555", marginBottom: 8, display: "block" },
  body: { padding: "0 24px 120px" },
  bigBtn: (c) => ({ display: "flex", alignItems: "center", justifyContent: "space-between", width: "100%", padding: "22px 28px", borderRadius: 14, border: "1px solid " + c + "33", background: c + "0d", color: c, fontSize: 17, fontWeight: 600, cursor: "pointer", marginTop: 16, fontFamily: "'DM Sans', sans-serif", transition: "opacity 0.15s" }),
  cardRow: (sel) => ({ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "16px 20px", borderRadius: 12, border: sel ? "1.5px solid " + gold : "1px solid #222", background: sel ? gold + "10" : "#141414", marginBottom: 10, cursor: "pointer" }),
  pill: (c) => ({ display: "inline-block", padding: "3px 10px", borderRadius: 20, background: (c || gold) + "18", color: c || gold, fontSize: 11, fontWeight: 500, marginLeft: 8 }),
  monthPill: (a) => ({ display: "inline-flex", alignItems: "center", padding: "8px 16px", borderRadius: 40, border: a ? "1.5px solid " + gold : "1px solid #2a2a2a", background: a ? gold + "18" : "#141414", color: a ? gold : "#888", fontSize: 13, fontWeight: 500, cursor: "pointer", margin: "4px 6px 4px 0", fontFamily: "'DM Sans', sans-serif" }),
  input: { width: "100%", background: "#141414", border: "1px solid #2a2a2a", borderRadius: 10, color: "#f0ece4", fontSize: 16, padding: "14px 16px", outline: "none", fontFamily: "'DM Sans', sans-serif", boxSizing: "border-box" },
  overlay: { position: "fixed", inset: 0, background: "rgba(0,0,0,0.75)", zIndex: 99 },
  sheet: { position: "fixed", bottom: 0, left: "50%", transform: "translateX(-50%)", width: "100%", maxWidth: 480, background: "#141414", borderRadius: "20px 20px 0 0", border: "1px solid #222", padding: "28px 24px 48px", zIndex: 100, boxShadow: "0 -20px 60px rgba(0,0,0,0.8)", maxHeight: "90vh", overflowY: "auto" },
  sheetTitle: { fontFamily: "'DM Mono', monospace", fontSize: 11, letterSpacing: "0.2em", color: "#555", textTransform: "uppercase", marginBottom: 20 },
  btn: (c) => ({ padding: "12px 20px", borderRadius: 10, border: "1px solid " + (c || gold) + "44", background: (c || gold) + "10", color: c || gold, fontSize: 14, fontWeight: 500, cursor: "pointer", fontFamily: "'DM Sans', sans-serif" }),
  dangerBtn: { padding: "12px 20px", borderRadius: 10, border: "1px solid #ff444422", background: "#ff44441a", color: "#ff6b6b", fontSize: 14, fontWeight: 500, cursor: "pointer", fontFamily: "'DM Sans', sans-serif" },
  backBtn: { background: "none", border: "none", color: gold, fontSize: 14, cursor: "pointer", padding: 0, marginBottom: 12, fontFamily: "'DM Sans', sans-serif" },
  receiptCard: { background: "#141414", border: "1px solid #222", borderRadius: 14, padding: "16px 18px", marginBottom: 12, display: "flex", gap: 14, alignItems: "center", cursor: "pointer" },
  receiptCardWrap: { position: "relative", marginBottom: 12, borderRadius: 14, overflow: "hidden" },
  deleteReveal: { position: "absolute", right: 0, top: 0, bottom: 0, width: 90, background: "#c0392b", display: "flex", alignItems: "center", justifyContent: "center", flexDirection: "column", gap: 4 },
  thumb: { width: 56, height: 56, borderRadius: 8, objectFit: "cover", background: "#1e1e1e", flexShrink: 0, border: "1px solid #2a2a2a" },
};

// ─── Upload Progress Sheet ────────────────────────────────────
function UploadProgressSheet({ total, done, onCancel }) {
  const pct = total > 0 ? Math.round((done / total) * 100) : 0;
  return (
    <>
      <div style={S.overlay} />
      <div style={{ ...S.sheet, display: "flex", flexDirection: "column", alignItems: "center", gap: 20 }}>
        <div style={S.sheetTitle}>Saving Receipts</div>
        <div style={{ fontFamily: "'DM Mono', monospace", fontSize: 36, color: gold }}>{done}/{total}</div>
        <div style={{ width: "100%", height: 6, background: "#222", borderRadius: 3, overflow: "hidden" }}>
          <div style={{ width: pct + "%", height: "100%", background: gold, borderRadius: 3, transition: "width 0.3s ease" }} />
        </div>
        <div style={{ color: "#555", fontSize: 13, fontFamily: "'DM Mono', monospace" }}>
          {done < total ? "Uploading…" : "Done!"}
        </div>
      </div>
    </>
  );
}

// ─── ConfirmSheet ─────────────────────────────────────────────
function ConfirmSheet({ title, message, onConfirm, onCancel }) {
  return (
    <>
      <div style={S.overlay} onClick={onCancel} />
      <div style={S.sheet}>
        <div style={S.sheetTitle}>{title}</div>
        <p style={{ color: "#aaa", fontSize: 15, marginBottom: 24 }}>{message}</p>
        <div style={{ display: "flex", gap: 12 }}>
          <button onClick={onCancel} style={{ ...S.btn("#888"), flex: 1 }}>Cancel</button>
          <button onClick={onConfirm} style={{ ...S.dangerBtn, flex: 1 }}>Delete</button>
        </div>
      </div>
    </>
  );
}

// ─── NewCardSheet ─────────────────────────────────────────────
function NewCardSheet({ onSave, onCancel, loading }) {
  const [name, setName] = useState("");
  return (
    <>
      <div style={S.overlay} onClick={onCancel} />
      <div style={S.sheet}>
        <div style={S.sheetTitle}>New Card</div>
        <div style={{ marginBottom: 20 }}>
          <label style={S.label}>Card Nickname</label>
          <input style={S.input} placeholder="e.g. Chase Visa, Amex Business…" value={name} onChange={e => setName(e.target.value)} autoFocus />
        </div>
        <div style={{ display: "flex", gap: 12 }}>
          <button onClick={onCancel} style={{ ...S.btn("#888"), flex: 1 }}>Cancel</button>
          <button disabled={!name.trim() || loading} onClick={() => onSave(name.trim())}
            style={{ ...S.btn(), flex: 1, opacity: (!name.trim() || loading) ? 0.4 : 1 }}>
            {loading ? "Saving…" : "Create Card"}
          </button>
        </div>
      </div>
    </>
  );
}

// ─── ReceiptViewer ────────────────────────────────────────────
function ReceiptViewer({ receipt, onClose, onDelete }) {
  const isPDF = receipt.mimeType === "application/pdf";
  const now = new Date(receipt.createdAt ? receipt.createdAt.toMillis() : Date.now());
  const dateLabel = receipt.createdAt
    ? now.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })
    : MONTHS[receipt.month] + " " + receipt.year;
  return (
    <div style={{ position: "fixed", inset: 0, zIndex: 200, background: "#000", display: "flex", flexDirection: "column" }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "16px 20px", borderBottom: "1px solid #1e1e1e" }}>
        <div>
          <div style={{ fontWeight: 600, fontSize: 16 }}>Receipt</div>
          <div style={{ color: "#888", fontSize: 13 }}>{dateLabel}</div>
        </div>
        <button onClick={onClose} style={{ background: "none", border: "none", color: "#888", fontSize: 24, cursor: "pointer" }}>✕</button>
      </div>
      <div style={{ flex: 1, overflow: "auto", display: "flex", alignItems: "center", justifyContent: "center", padding: 20 }}>
        {isPDF
          ? <iframe src={receipt.downloadUrl} style={{ width: "100%", height: "70vh", border: "none", borderRadius: 8 }} title="receipt" />
          : <img src={receipt.downloadUrl} alt="receipt" style={{ maxWidth: "100%", maxHeight: "70vh", borderRadius: 8, objectFit: "contain" }} />
        }
      </div>
      <div style={{ padding: "16px 20px 40px", display: "flex", gap: 10, borderTop: "1px solid #1e1e1e" }}>
        <a href={receipt.downloadUrl} target="_blank" rel="noreferrer"
          style={{ ...S.btn(), textDecoration: "none", textAlign: "center", flex: 1 }}>Full Size</a>
        <button onClick={() => onDelete(receipt)} style={{ ...S.dangerBtn, flex: 1 }}>Delete</button>
      </div>
    </div>
  );
}

// ─── SwipeableReceiptRow ──────────────────────────────────────
function SwipeableReceiptRow({ r, onOpen, onDeleteRequest }) {
  const [offset, setOffset] = useState(0);
  const [swiping, setSwiping] = useState(false);
  const startXRef = useRef(null);
  const startYRef = useRef(null);
  const THRESHOLD = 72;
  const MAX = 90;

  function onTouchStart(e) {
    startXRef.current = e.touches[0].clientX;
    startYRef.current = e.touches[0].clientY;
    setSwiping(true);
  }
  function onTouchMove(e) {
    if (startXRef.current === null) return;
    const dx = startXRef.current - e.touches[0].clientX;
    const dy = Math.abs(e.touches[0].clientY - startYRef.current);
    if (dy > 14 && Math.abs(dx) < dy) { setSwiping(false); startXRef.current = null; return; }
    if (dx > 0) {
      e.preventDefault();
      setOffset(Math.min(dx, MAX));
    }
  }
  function onTouchEnd() {
    if (offset >= THRESHOLD) {
      setOffset(MAX);
      onDeleteRequest();
      setTimeout(() => setOffset(0), 500);
    } else {
      setOffset(0);
    }
    startXRef.current = null;
    setSwiping(false);
  }

  const dateLabel = r.createdAt
    ? new Date(r.createdAt.toMillis()).toLocaleDateString("en-US", { month: "short", day: "numeric" })
    : "";

  return (
    <div style={S.receiptCardWrap}>
      <div style={{ ...S.deleteReveal, opacity: offset > 10 ? 1 : 0 }}>
        <span style={{ fontSize: 20 }}>🗑</span>
        <span style={{ color: "#fff", fontSize: 11, fontFamily: "'DM Mono', monospace", letterSpacing: "0.1em" }}>DELETE</span>
      </div>
      <div
        onTouchStart={onTouchStart}
        onTouchMove={onTouchMove}
        onTouchEnd={onTouchEnd}
        onClick={() => offset === 0 && onOpen()}
        style={{
          ...S.receiptCard,
          marginBottom: 0,
          transform: "translateX(-" + offset + "px)",
          transition: swiping ? "none" : "transform 0.25s ease",
          userSelect: "none",
          WebkitUserSelect: "none",
        }}
      >
        {r.mimeType === "application/pdf"
          ? <div style={{ ...S.thumb, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 22 }}>📄</div>
          : <img src={r.downloadUrl} alt="" style={S.thumb} />
        }
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontWeight: 500, fontSize: 15, marginBottom: 3, color: "#f0ece4" }}>Receipt</div>
          <div style={{ color: "#555", fontFamily: "'DM Mono', monospace", fontSize: 13 }}>{dateLabel}</div>
        </div>
        <div style={{ color: "#333", fontSize: 20 }}>›</div>
      </div>
    </div>
  );
}

// ─── MonthReceiptsScreen ──────────────────────────────────────
function MonthReceiptsScreen({ card, year, month, onBack }) {
  const [receipts, setReceipts] = useState([]);
  const [loading, setLoading] = useState(true);
  const [viewer, setViewer] = useState(null);
  const [confirmDelete, setConfirmDelete] = useState(null);
  const [uploading, setUploading] = useState(false);
  const [uploadDone, setUploadDone] = useState(0);
  const [uploadTotal, setUploadTotal] = useState(0);
  const [printing, setPrinting] = useState(false);
  const fileRef = useRef();

  useEffect(() => { fetchReceipts(); }, []);

  async function fetchReceipts() {
    setLoading(true);
    setReceipts(await loadReceipts(card.id, year, month));
    setLoading(false);
  }

  async function handleFiles(files) {
    if (!files || files.length === 0) return;
    setUploadTotal(files.length);
    setUploadDone(0);
    setUploading(true);
    for (const file of files) {
      const base64 = await readFileAsBase64(file);
      await saveReceipt({ cardId: card.id, cardName: card.name, year, month, fileBase64: base64, fileName: file.name, mimeType: file.type });
      setUploadDone(prev => prev + 1);
    }
    setUploading(false);
    fetchReceipts();
  }

  async function handleDelete(receipt) {
    await deleteReceipt(receipt);
    setViewer(null);
    setConfirmDelete(null);
    fetchReceipts();
  }

  async function handlePrintAll() {
    if (receipts.length === 0) return;
    setPrinting(true);
    try {
      // Fetch all images as data URLs so they work offline/cross-origin in the print window
      const items = await Promise.all(receipts.map(async (r, i) => {
        const dateLabel = r.createdAt
          ? new Date(r.createdAt.toMillis()).toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" })
          : MONTHS[r.month] + " " + r.year;
        if (r.mimeType === "application/pdf") {
          return { index: i + 1, dateLabel, isPDF: true, url: r.downloadUrl };
        }
        try {
          const resp = await fetch(r.downloadUrl);
          const blob = await resp.blob();
          const dataUrl = await readFileAsDataURL(blob);
          return { index: i + 1, dateLabel, isPDF: false, dataUrl };
        } catch {
          return { index: i + 1, dateLabel, isPDF: false, dataUrl: r.downloadUrl };
        }
      }));

      const summaryRows = items.map(it =>
        `<tr>
          <td style="padding:10px 14px;border-bottom:1px solid #e8e8e8;font-family:monospace;color:#555;">${it.index}</td>
          <td style="padding:10px 14px;border-bottom:1px solid #e8e8e8;">${it.dateLabel}</td>
          <td style="padding:10px 14px;border-bottom:1px solid #e8e8e8;color:#888;">${it.isPDF ? "PDF Document" : "Image"}</td>
        </tr>`
      ).join("");

      const receiptPages = items.map(it => {
        if (it.isPDF) {
          return `<div class="page">
            <div class="page-header">
              <span class="page-num">Receipt ${it.index} of ${items.length}</span>
              <span class="page-date">${it.dateLabel}</span>
            </div>
            <div style="display:flex;align-items:center;justify-content:center;height:80vh;flex-direction:column;gap:16px;color:#888;">
              <div style="font-size:64px;">📄</div>
              <div style="font-size:16px;font-family:monospace;">PDF — open original to view</div>
              <a href="${it.url}" style="color:#cc2222;font-size:14px;" target="_blank">${it.url.substring(0, 60)}…</a>
            </div>
          </div>`;
        }
        return `<div class="page">
          <div class="page-header">
            <span class="page-num">Receipt ${it.index} of ${items.length}</span>
            <span class="page-date">${it.dateLabel}</span>
          </div>
          <div style="display:flex;align-items:center;justify-content:center;flex:1;">
            <img src="${it.dataUrl}" style="max-width:100%;max-height:88vh;object-fit:contain;" />
          </div>
        </div>`;
      }).join("");

      const html = `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>IPS Expenses — ${card.name} — ${MONTHS[month]} ${year}</title>
<style>
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body { font-family: 'Helvetica Neue', Arial, sans-serif; background: #fff; color: #1a1a1a; }
  .cover { padding: 64px 56px; min-height: 100vh; display: flex; flex-direction: column; justify-content: center; page-break-after: always; }
  .cover-logo { font-size: 13px; letter-spacing: 0.25em; text-transform: uppercase; color: #cc2222; font-weight: 700; margin-bottom: 48px; }
  .cover-title { font-size: 42px; font-weight: 700; line-height: 1.1; margin-bottom: 12px; }
  .cover-sub { font-size: 20px; color: #555; margin-bottom: 48px; }
  .cover-meta { display: flex; gap: 40px; margin-bottom: 48px; }
  .cover-meta-item label { display: block; font-size: 11px; letter-spacing: 0.15em; text-transform: uppercase; color: #aaa; margin-bottom: 4px; }
  .cover-meta-item value { font-size: 18px; font-weight: 500; font-family: monospace; }
  .summary-table { width: 100%; border-collapse: collapse; margin-top: 32px; }
  .summary-table th { text-align: left; padding: 12px 14px; border-bottom: 2px solid #1a1a1a; font-size: 11px; letter-spacing: 0.15em; text-transform: uppercase; color: #888; }
  .page { padding: 24px 32px; min-height: 100vh; display: flex; flex-direction: column; page-break-after: always; }
  .page-header { display: flex; justify-content: space-between; align-items: center; padding-bottom: 16px; border-bottom: 1px solid #e8e8e8; margin-bottom: 24px; }
  .page-num { font-size: 11px; letter-spacing: 0.15em; text-transform: uppercase; color: #aaa; font-family: monospace; }
  .page-date { font-size: 14px; color: #555; }
  @media print {
    @page { margin: 0; size: letter; }
    body { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  }
</style>
</head>
<body>
  <div class="cover">
    <div class="cover-logo">Internal Pipeline Services</div>
    <div class="cover-title">${MONTHS[month]} ${year}</div>
    <div class="cover-sub">${card.name}</div>
    <div class="cover-meta">
      <div class="cover-meta-item"><label>Receipts</label><value>${items.length}</value></div>
      <div class="cover-meta-item"><label>Printed</label><value>${new Date().toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}</value></div>
    </div>
    <table class="summary-table">
      <thead><tr>
        <th>#</th><th>Date</th><th>Type</th>
      </tr></thead>
      <tbody>${summaryRows}</tbody>
    </table>
  </div>
  ${receiptPages}
</body>
</html>`;

      const win = window.open("", "_blank");
      win.document.write(html);
      win.document.close();
      win.onload = () => { win.focus(); win.print(); };
    } finally {
      setPrinting(false);
    }
  }

  return (
    <div style={S.app}>
      <div style={S.header}>
        <button onClick={onBack} style={S.backBtn}>← Back</button>
        <div style={{ ...S.mono, fontSize: 11, letterSpacing: "0.15em", color: "#555", textTransform: "uppercase", marginBottom: 4 }}>{card.name}</div>
        <div style={{ fontSize: 22, fontWeight: 600 }}>{MONTHS[month]} {year}</div>
        {receipts.length > 0 && <div style={{ color: "#888", fontSize: 13, marginTop: 4 }}>{receipts.length} receipt{receipts.length !== 1 ? "s" : ""}</div>}
      </div>
      <div style={S.body}>
        <input ref={fileRef} type="file" accept="image/*,application/pdf" multiple style={{ display: "none" }}
          onChange={e => { const files = Array.from(e.target.files || []); e.target.value = ""; handleFiles(files); }} />
        <button onClick={() => fileRef.current.click()} style={S.bigBtn(gold)}>
          <span>Upload Receipt</span><span style={{ fontSize: 22 }}>↑</span>
        </button>
        {receipts.length > 0 && (
          <button onClick={handlePrintAll} disabled={printing} style={{ ...S.bigBtn("#5b9cf6"), opacity: printing ? 0.5 : 1 }}>
            <span>{printing ? "Preparing…" : "Print All"}</span>
            <span style={{ fontSize: 22 }}>🖨</span>
          </button>
        )}
        {loading && <div style={{ color: "#333", fontSize: 12, textAlign: "center", marginTop: 48, fontFamily: "'DM Mono', monospace", letterSpacing: "0.15em" }}>LOADING…</div>}
        {!loading && receipts.length === 0 && <div style={{ textAlign: "center", color: "#444", fontSize: 14, marginTop: 60 }}>No receipts for {MONTHS[month]} {year}</div>}
        <div style={{ marginTop: 24 }}>
          {receipts.map(r => (
            <SwipeableReceiptRow key={r.id} r={r} onOpen={() => setViewer(r)} onDeleteRequest={() => setConfirmDelete(r)} />
          ))}
        </div>
      </div>
      {uploading && <UploadProgressSheet total={uploadTotal} done={uploadDone} />}
      {viewer && <ReceiptViewer receipt={viewer} onClose={() => setViewer(null)} onDelete={r => setConfirmDelete(r)} />}
      {confirmDelete && <ConfirmSheet title="Delete Receipt" message="Delete this receipt? This cannot be undone." onConfirm={() => handleDelete(confirmDelete)} onCancel={() => setConfirmDelete(null)} />}
    </div>
  );
}

// ─── MenuScreen ───────────────────────────────────────────────
function MenuScreen({ cards, defaultCardId, onSetDefault, onRefreshCards, onSelectMonth, onBack }) {
  const [selectedCard, setSelectedCard] = useState(defaultCardId || (cards[0] && cards[0].id) || null);
  const [showNewCard, setShowNewCard] = useState(false);
  const [cardLoading, setCardLoading] = useState(false);
  const [confirmDeleteCard, setConfirmDeleteCard] = useState(null);
  const now = new Date();
  const [selectedYear, setSelectedYear] = useState(now.getFullYear());
  const years = [now.getFullYear(), now.getFullYear() - 1, now.getFullYear() - 2];

  async function handleNewCard(name) {
    setCardLoading(true);
    const id = await createCard(name);
    await onRefreshCards();
    setSelectedCard(id);
    setCardLoading(false);
    setShowNewCard(false);
  }

  async function handleDeleteCard(c) {
    await deleteCard(c.id);
    await onRefreshCards();
    if (selectedCard === c.id) setSelectedCard((cards.find(x => x.id !== c.id) || {}).id || null);
    setConfirmDeleteCard(null);
  }

  const card = cards.find(c => c.id === selectedCard);

  return (
    <div style={S.app}>
      <div style={S.header}>
        <button onClick={onBack} style={S.backBtn}>← Back</button>
        <div style={{ ...S.mono, fontSize: 11, letterSpacing: "0.15em", color: "#555", textTransform: "uppercase", marginBottom: 4 }}>IPS Expenses</div>
        <div style={{ fontSize: 22, fontWeight: 600 }}>Menu</div>
      </div>
      <div style={S.body}>
        <div style={{ marginTop: 28 }}>
          <div style={{ ...S.label, marginBottom: 14 }}>Cards</div>
          {cards.length === 0 && <div style={{ color: "#444", fontSize: 14, marginBottom: 16 }}>No cards yet — add one below</div>}
          {cards.map(c => (
            <div key={c.id} style={S.cardRow(c.id === selectedCard)} onClick={() => setSelectedCard(c.id)}>
              <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
                <div style={{ width: 38, height: 38, borderRadius: 8, background: c.id === selectedCard ? gold + "15" : "#1e1e1e", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 18 }}>💳</div>
                <div>
                  <span style={{ fontWeight: 500, fontSize: 15 }}>{c.name}</span>
                  {c.id === defaultCardId && <span style={S.pill()}>Default</span>}
                </div>
              </div>
              <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
                {c.id !== defaultCardId && (
                  <button onClick={e => { e.stopPropagation(); onSetDefault(c.id); }} style={{ ...S.btn("#555"), fontSize: 12, padding: "6px 12px" }}>
                    Set Default
                  </button>
                )}
                <button onClick={e => { e.stopPropagation(); setConfirmDeleteCard(c); }} style={{ background: "none", border: "none", color: "#3a3a3a", fontSize: 18, cursor: "pointer", padding: "4px 8px" }}>🗑</button>
              </div>
            </div>
          ))}
          <button onClick={() => setShowNewCard(true)} style={S.bigBtn("#888")}>
            <span>New Card</span><span style={{ fontSize: 22 }}>+</span>
          </button>
        </div>

        {selectedCard && card && (
          <div style={{ marginTop: 36 }}>
            <div style={{ ...S.label, marginBottom: 14 }}>Browse Receipts — {card.name}</div>
            <div style={{ display: "flex", gap: 8, marginBottom: 16, flexWrap: "wrap" }}>
              {years.map(y => (
                <button key={y} onClick={() => setSelectedYear(y)} style={S.monthPill(y === selectedYear)}>{y}</button>
              ))}
            </div>
            <div style={{ display: "flex", flexWrap: "wrap" }}>
              {MONTHS.map((m, i) => (
                <button key={m} onClick={() => onSelectMonth(card, selectedYear, i)} style={S.monthPill(false)}>{m.slice(0, 3)}</button>
              ))}
            </div>
          </div>
        )}
      </div>
      {showNewCard && <NewCardSheet onSave={handleNewCard} onCancel={() => setShowNewCard(false)} loading={cardLoading} />}
      {confirmDeleteCard && <ConfirmSheet title="Delete Card" message={"Delete \"" + confirmDeleteCard.name + "\"? Receipts already saved will not be removed."} onConfirm={() => handleDeleteCard(confirmDeleteCard)} onCancel={() => setConfirmDeleteCard(null)} />}
    </div>
  );
}

// ─── PinSheet ─────────────────────────────────────────────────
function PinSheet({ onUnlock, onCancel }) {
  const [digits, setDigits] = useState("");
  const [shake, setShake] = useState(false);

  function handleDigit(d) {
    if (digits.length >= 4) return;
    const next = digits + d;
    setDigits(next);
    if (next.length === 4) {
      if (next === MENU_PIN) {
        setTimeout(() => { onUnlock(); setDigits(""); }, 120);
      } else {
        setShake(true);
        setTimeout(() => { setShake(false); setDigits(""); }, 500);
      }
    }
  }

  function handleBack() { setDigits(digits.slice(0, -1)); }

  const dotStyle = (filled) => ({
    width: 14, height: 14, borderRadius: "50%",
    background: filled ? gold : "transparent",
    border: "2px solid " + (filled ? gold : "#444"),
    transition: "background 0.1s, border-color 0.1s"
  });

  const keyStyle = {
    width: 72, height: 72, borderRadius: 16,
    background: "#1a1a1a", border: "1px solid #2a2a2a",
    color: "#f0ece4", fontSize: 22, fontWeight: 500,
    cursor: "pointer", fontFamily: "'DM Sans', sans-serif",
    display: "flex", alignItems: "center", justifyContent: "center"
  };

  const keys = ["1","2","3","4","5","6","7","8","9","","0","⌫"];

  return (
    <>
      <div style={S.overlay} onClick={onCancel} />
      <div style={S.sheet}>
        <div style={S.sheetTitle}>Enter PIN to access Menu</div>
        <div style={{ display: "flex", justifyContent: "center", gap: 20, marginBottom: 36,
          animation: shake ? "shake 0.4s ease" : "none" }}>
          {[0,1,2,3].map(i => <div key={i} style={dotStyle(i < digits.length)} />)}
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 12, maxWidth: 280, margin: "0 auto" }}>
          {keys.map((k, i) => (
            k === ""
              ? <div key={i} />
              : k === "⌫"
                ? <button key={i} onClick={handleBack} style={{ ...keyStyle, color: "#888" }}>⌫</button>
                : <button key={i} onClick={() => handleDigit(k)} style={keyStyle}>{k}</button>
          ))}
        </div>
        <button onClick={onCancel} style={{ ...S.btn("#555"), width: "100%", marginTop: 28, textAlign: "center" }}>Cancel</button>
      </div>
      <style>{`@keyframes shake { 0%,100%{transform:translateX(0)} 20%{transform:translateX(-8px)} 40%{transform:translateX(8px)} 60%{transform:translateX(-6px)} 80%{transform:translateX(6px)} }`}</style>
    </>
  );
}

// ─── HomeScreen ───────────────────────────────────────────────
function HomeScreen({ cards, defaultCardId, onNewExpense, onUpload, onMenu }) {
  const card = cards.find(c => c.id === defaultCardId) || cards[0];
  const now = new Date();
  return (
    <div style={S.app}>
      <div style={S.header}>
        <div style={{ ...S.mono, fontSize: 11, letterSpacing: "0.2em", color: "#555", textTransform: "uppercase", marginBottom: 4 }}>IPS Expenses</div>
        <div style={{ fontSize: 22, fontWeight: 600 }}>{card ? card.name : "No card set"}</div>
        <div style={{ color: "#555", fontSize: 13, marginTop: 6, fontFamily: "'DM Mono', monospace" }}>{MONTHS[now.getMonth()]} {now.getFullYear()}</div>
      </div>
      <div style={S.body}>
        <div style={{ marginTop: 48 }}>
          {card
            ? <button onClick={onNewExpense} style={S.bigBtn(gold)}><span>New Expense</span><span style={{ fontSize: 28 }}>📷</span></button>
            : <div style={{ ...S.bigBtn("#444"), cursor: "default", opacity: 0.35 }}><span>New Expense</span><span style={{ fontSize: 28 }}>📷</span></div>
          }
          {card
            ? <button onClick={onUpload} style={S.bigBtn("#5b9cf6")}><span>Upload Receipt</span><span style={{ fontSize: 24 }}>📄</span></button>
            : <div style={{ ...S.bigBtn("#444"), cursor: "default", opacity: 0.35 }}><span>Upload Receipt</span><span style={{ fontSize: 24 }}>📄</span></div>
          }
          {!card && <p style={{ color: "#555", fontSize: 13, textAlign: "center", marginTop: 12 }}>Add a card in Menu to get started</p>}
          <button onClick={onMenu} style={S.bigBtn("#888")}><span>Menu</span><span style={{ fontSize: 22 }}>☰</span></button>
        </div>
      </div>
    </div>
  );
}

// ─── App ──────────────────────────────────────────────────────
function App() {
  const [screen, setScreen] = useState("home");
  const [cards, setCards] = useState([]);
  const [defaultCardId, setDefaultCardId] = useState(() => localStorage.getItem("ips_default_card"));
  const [cardsLoaded, setCardsLoaded] = useState(false);
  const [monthCtx, setMonthCtx] = useState(null);
  const [menuUnlocked, setMenuUnlocked] = useState(false);
  const [showPin, setShowPin] = useState(false);
  const [uploading, setUploading] = useState(false);
  const [uploadDone, setUploadDone] = useState(0);
  const [uploadTotal, setUploadTotal] = useState(0);
  const cameraRef = useRef();
  const uploadRef = useRef();

  useEffect(() => { fetchCards(); checkSharedFile(); }, []);

  async function fetchCards() {
    const c = await loadCards();
    setCards(c);
    if (c.length > 0 && !localStorage.getItem("ips_default_card")) {
      setDefaultCardId(c[0].id);
      localStorage.setItem("ips_default_card", c[0].id);
    }
    setCardsLoaded(true);
  }

  async function checkSharedFile() {
    if (!window.location.search.includes("shared=true")) return;
    window.history.replaceState({}, "", "/");
    try {
      const shareCache = await caches.open("ips-share-target");
      const response = await shareCache.match("/shared-file");
      if (!response) return;
      const blob = await response.blob();
      const fileName = response.headers.get("X-File-Name") || "receipt";
      const mimeType = response.headers.get("Content-Type") || "image/jpeg";
      await shareCache.delete("/shared-file");
      await handleFiles([new File([blob], fileName, { type: mimeType })]);
    } catch (e) {}
  }

  async function handleFiles(files) {
    if (!files || files.length === 0) return;
    const card = cards.find(c => c.id === defaultCardId) || cards[0];
    if (!card) return;
    const now = new Date();
    const year = now.getFullYear();
    const month = now.getMonth();
    setUploadTotal(files.length);
    setUploadDone(0);
    setUploading(true);
    for (const file of files) {
      const base64 = await readFileAsBase64(file);
      await saveReceipt({ cardId: card.id, cardName: card.name, year, month, fileBase64: base64, fileName: file.name, mimeType: file.type });
      setUploadDone(prev => prev + 1);
    }
    setUploading(false);
  }

  function handleSetDefault(id) {
    setDefaultCardId(id);
    localStorage.setItem("ips_default_card", id);
  }

  if (!cardsLoaded) {
    return (
      <div style={{ ...S.app, display: "flex", alignItems: "center", justifyContent: "center" }}>
        <div style={{ color: "#333", fontFamily: "'DM Mono', monospace", fontSize: 12, letterSpacing: "0.2em" }}>LOADING…</div>
      </div>
    );
  }

  return (
    <>
      <style>{`
        * { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; }
        body { background: #0f0f0f; }
        input:focus { border-color: ${gold} !important; box-shadow: 0 0 0 2px ${gold}18; }
        button:active { opacity: 0.7 !important; transform: scale(0.98); }
        @keyframes pulse { 0%,100%{opacity:1} 50%{opacity:0.3} }
        ::-webkit-scrollbar { width: 4px; }
        ::-webkit-scrollbar-thumb { background: #2a2a2a; border-radius: 4px; }
      `}</style>

      <input ref={cameraRef} type="file" accept="image/*" capture="environment" style={{ display: "none" }}
        onChange={e => { const f = e.target.files?.[0]; e.target.value = ""; if (f) handleFiles([f]); }} />
      <input ref={uploadRef} type="file" accept="image/*,application/pdf" multiple style={{ display: "none" }}
        onChange={e => { const files = Array.from(e.target.files || []); e.target.value = ""; if (files.length > 0) handleFiles(files); }} />

      {screen === "home" && <HomeScreen cards={cards} defaultCardId={defaultCardId} onNewExpense={() => cameraRef.current.click()} onUpload={() => uploadRef.current.click()} onMenu={() => { if (menuUnlocked) { setScreen("menu"); } else { setShowPin(true); } }} />}
      {screen === "menu" && <MenuScreen cards={cards} defaultCardId={defaultCardId} onSetDefault={handleSetDefault} onRefreshCards={fetchCards} onSelectMonth={(card, year, month) => { setMonthCtx({ card, year, month }); setScreen("month"); }} onBack={() => setScreen("home")} />}
      {screen === "month" && monthCtx && <MonthReceiptsScreen card={monthCtx.card} year={monthCtx.year} month={monthCtx.month} onBack={() => setScreen("menu")} />}
      {showPin && <PinSheet onUnlock={() => { setMenuUnlocked(true); setShowPin(false); setScreen("menu"); }} onCancel={() => setShowPin(false)} />}
      {uploading && <UploadProgressSheet total={uploadTotal} done={uploadDone} />}
    </>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
