// screens/dashboard.jsx — Arco Rooms home (academic-year primary view)
// Focused on the year-round work of running room-by-room lets: occupancy,
// money in vs out, and who still owes. Includes a small summer "preview"
// card that links into the dedicated Summer section.

function Dashboard({ ctx }) {
  const { data, nav, openAddTenant, markPaid } = ctx;
  const tt = ctx.tt;

  // ── Derived numbers ──
  const totalRooms = data.apartments.reduce((s, a) =>
    s + (a.type === "rooms" ? a.bedrooms : 1), 0);
  const occupiedRooms = data.tenants.filter((t) => t.status === "active").length;
  const occupancy = Math.round((occupiedRooms / totalRooms) * 100);

  const thisMonthBills = data.bills.filter((b) => b.period === "2026-05");
  const incomeMonth = thisMonthBills.filter((b) => b.status === "paid").reduce((s, b) => s + b.amount, 0);
  const outstandingMonth = thisMonthBills.filter((b) => b.status !== "paid").reduce((s, b) => s + b.amount, 0);
  const expensesMonth = data.expenses.filter((e) => e.date.startsWith("2026-05")).reduce((s, e) => s + e.amount, 0);

  const overdueBills = data.bills.filter((b) => b.status === "overdue");
  const pendingBills = data.bills.filter((b) => b.status === "pending" && b.period === "2026-05");
  const openTickets = data.tickets.filter((t) => t.status !== "resolved");
  const highTickets = openTickets.filter((t) => t.priority === "high");

  // Summer preview — small widget linking into the Summer section.
  const summerConfirmed = data.bookings.filter((b) => b.status === "confirmed" && b.nightly > 0 && b.start >= "2026-06-01" && b.start < "2026-09-01");
  const summerNts = summerConfirmed.reduce((s, b) => s + nightsBetween(b.start, b.end), 0);
  const summerRev = summerConfirmed.reduce((s, b) => s + nightsBetween(b.start, b.end) * b.nightly, 0);
  const todayISO = ArcoData.ISO(ArcoData.today);
  const nextSummerArrival = data.bookings
    .filter((b) => b.status !== "blocked" && b.status !== "resident" && b.start >= todayISO && b.start < "2026-09-01")
    .sort((a, b) => a.start.localeCompare(b.start))[0];
  const daysToSummerArrival = nextSummerArrival
    ? Math.round((new Date(nextSummerArrival.start) - new Date(todayISO)) / 86400000)
    : null;

  // Greeting based on hour (localized)
  const greet = (() => {
    const h = new Date().getHours();
    if (h < 12) return tt("time.morning");
    if (h < 19) return tt("time.afternoon");
    return tt("time.evening");
  })();

  return (
    <>
      <div className="main-top">
        <div className="title">
          <h1 className="display">{greet}, Sergio</h1>
          <div className="sub">
            {fmtDate(todayISO, { withYear: true })}
            {" · "}
            <span className="muted-2 b500">{tt("dash.sub.summary", { occ: occupiedRooms, total: totalRooms, n: data.apartments.length })}</span>
          </div>
        </div>
        <div className="actions">
          <button className="searchbar searchbar-btn" onClick={ctx.openCommandPalette}
                  aria-label={tt("search.placeholder")}>
            <Icon name="search" size={14} />
            <span className="muted txt-sm" style={{ flex: 1, textAlign: "left" }}>{tt("search.placeholder")}</span>
            <span className="kbd">⌘K</span>
          </button>
          <HeaderTools ctx={ctx} />
          <button className="btn primary" onClick={openAddTenant}>
            <Icon name="plus" size={14} /> {tt("btn.addTenant")}
          </button>
        </div>
      </div>

      <div className="main-scroll">
        {/* ── AI moat hero — what did the assistant handle for you today? ── */}
        <AICard ctx={ctx} />

        {/* ── Editorial KPI row — replaces the generic 4-up `grid-stat-4`
              SaaS template. Two big numbers (Cobrado, Pendiente) carry the
              page; Ocupación + Gastos sit smaller as supporting context.
              The Outstanding number is the click-anchor to #pendientes. ── */}
        <div className="editorial-kpi">
          <div className="ed-kpi big">
            <div className="lbl"><Icon name="euro" size={11} /> {tt("dash.stat.collected")}</div>
            <div className="val mono">{fmtEUR(incomeMonth, { decimals: false })}</div>
            <div className="sub">
              <span style={{ color: "var(--ef-accent-deep)", fontWeight: 500 }}>+0,7%</span> {tt("time.vs", { period: "abr" }) || "vs Abr"}
            </div>
          </div>

          <button className="ed-kpi big interactive"
                  onClick={() => {
                    const el = document.getElementById("pendientes");
                    if (el) el.scrollIntoView({ behavior: "smooth", block: "start" });
                  }}
                  aria-label={tt("dash.stat.outstanding")}>
            <div className="lbl"><Icon name="clock" size={11} /> {tt("dash.stat.outstanding")}</div>
            <div className="val mono" style={{ color: outstandingMonth > 0 ? "var(--ef-warn)" : "var(--ef-ink)" }}>
              {fmtEUR(outstandingMonth, { decimals: false })}
            </div>
            <div className="sub" style={{ color: outstandingMonth > 0 ? "var(--ef-warn)" : "var(--ef-muted)" }}>
              {tt("dash.stat.outstandingSub", { n: thisMonthBills.filter((b) => b.status !== "paid").length })}
              <Icon name="chevR" size={11} style={{ marginLeft: 4, verticalAlign: "middle" }} />
            </div>
          </button>

          <div className="ed-kpi support">
            <div className="lbl"><Icon name="home" size={11} /> {tt("dash.stat.occupancy")}</div>
            <div className="val-row">
              <span className="val mono">{occupancy}%</span>
              <div className="meter" aria-hidden>
                <i style={{ width: `${Math.min(100, occupancy)}%` }} />
              </div>
            </div>
            <div className="sub">{tt("dash.stat.occupancySub", { occ: occupiedRooms, total: totalRooms })}</div>
          </div>

          <div className="ed-kpi support">
            <div className="lbl"><Icon name="receipt" size={11} /> {tt("dash.stat.expenses")}</div>
            <div className="val mono small">{fmtEUR(expensesMonth, { decimals: false })}</div>
            <div className="sub">{tt("dash.stat.expensesSub", { n: data.expenses.filter((e) => e.date.startsWith("2026-05")).length })}</div>
          </div>
        </div>

        {/* ── Tus propiedades — heart of the academic-year view ── */}
        <PropertyGrid ctx={ctx} />

        {/* ── Pendientes este mes — promoted above cashflow so the
              first question "did rent come in?" gets answered at a glance.
              Renders the merged "needs attention" feed:
              overdue + pending bills + high-priority maintenance tickets,
              each row with a confirm popover for markPaid.
              Empty state is intentional — quiet wins are visible. ── */}
        <Pendientes ctx={ctx} />

        {/* ── Summer mini-link — quiet pointer to the dedicated section.
              Cashflow and detailed Occupancy now live exclusively on /finances
              (Reports tab) and on each apartment-detail page; the dashboard
              stays focused on "what to do today". ── */}
        {summerConfirmed.length > 0 && (
          <button className="summer-mini-link"
                  onClick={() => nav("summer")}
                  aria-label={tt("dash.summerCard")}>
            <div className="ic"><Icon name="sun" size={14} /></div>
            <div className="grow">
              <div className="b500">{tt("dash.summerCard")}</div>
              <div className="txt-xs muted">
                {tt("dash.summerCard.sub", { n: summerConfirmed.length, nts: summerNts, amt: fmtEUR(summerRev) })}
                {nextSummerArrival && ` · ${tt("dash.nextArrival", {
                  date: fmtDate(nextSummerArrival.start, { short: true }),
                  days: daysToSummerArrival,
                  guest: nextSummerArrival.guestName,
                })}`}
              </div>
            </div>
            <Icon name="chevR" size={14} className="muted" />
          </button>
        )}
      </div>
    </>
  );
}

// Helper — nights between two YYYY-MM-DD strings
function nightsBetween(start, end) {
  const a = new Date(start), b = new Date(end);
  return Math.max(0, Math.round((b - a) / 86400000));
}

// ───────────────────────── PROPERTY GRID ─────────────────────────
// Dashboard hero: a visual snapshot of every apartment and every room
// status at a glance. Each room is a tinted tile (PAID green, PENDING
// amber, OVERDUE red, VACANT dashed-outline). Whole-flat apartments
// render as a single tile spanning the grid.
function PropertyGrid({ ctx }) {
  const { data, nav, markPaid } = ctx;
  const tt = ctx.tt;
  const [view, setView] = React.useState("grid");

  // Carousel: horizontal scroll + floating arrows
  const carouselRef = React.useRef(null);
  const [canPrev, setCanPrev] = React.useState(false);
  const [canNext, setCanNext] = React.useState(true);
  const updateArrows = React.useCallback(() => {
    const el = carouselRef.current;
    if (!el) return;
    setCanPrev(el.scrollLeft > 2);
    setCanNext(el.scrollLeft + el.clientWidth < el.scrollWidth - 2);
  }, []);
  React.useEffect(() => {
    if (view !== "grid") return;
    updateArrows();
    const el = carouselRef.current;
    if (!el) return;
    el.addEventListener("scroll", updateArrows, { passive: true });
    window.addEventListener("resize", updateArrows);
    return () => {
      el.removeEventListener("scroll", updateArrows);
      window.removeEventListener("resize", updateArrows);
    };
  }, [view, updateArrows]);
  const scrollBy = (dir) => {
    const el = carouselRef.current;
    if (!el) return;
    const card = el.querySelector(".property-card.mini");
    const step = card ? card.getBoundingClientRect().width + 12 : 300;
    el.scrollBy({ left: dir * step * 2, behavior: "smooth" });
  };

  // Roll-up numbers for the section header
  const totalRooms    = data.apartments.reduce((s, a) => s + (a.type === "rooms" ? a.bedrooms : 1), 0);
  const occupiedRooms = data.tenants.filter((t) => t.status === "active").length;
  const paidThisMonth = data.tenants.filter((t) => {
    if (t.status !== "active") return false;
    const b = data.bills.find((bb) => bb.tenantId === t.id && bb.period === "2026-05" && bb.type === "rent");
    return b?.status === "paid";
  }).length;

  // Compute card data for each apartment once
  const cards = data.apartments.map((a) => {
    const rooms = a.type === "rooms" ? a.bedrooms : 1;
    const rentBill = (tenantId) =>
      data.bills.find((b) => b.tenantId === tenantId && b.period === "2026-05" && b.type === "rent");

    const cells = a.type === "rooms"
      ? Array.from({ length: a.bedrooms }, (_, i) => {
          const roomNum = i + 1;
          const tenant = data.tenants.find((t) => t.aptId === a.id && t.room === roomNum && t.status === "active");
          if (!tenant) return { kind: "vacant", roomNum };
          const bill = rentBill(tenant.id);
          return { kind: "tenant", roomNum, tenant, status: bill?.status || "pending", bill };
        })
      : [(() => {
          const tenant = data.tenants.find((t) => t.aptId === a.id && t.status === "active");
          if (!tenant) return { kind: "vacant-whole" };
          const bill = rentBill(tenant.id);
          return { kind: "whole", tenant, status: bill?.status || "pending", bill };
        })()];

    const occupied = cells.filter((c) => c.kind === "tenant" || c.kind === "whole").length;
    const vacant = cells.filter((c) => c.kind === "vacant" || c.kind === "vacant-whole").length;

    const hasOverdue = cells.some((c) => c.status === "overdue");
    const hasPending = cells.some((c) => c.status === "pending");
    const flagTone = hasOverdue ? "danger" : hasPending ? "warn" : "positive";

    const monthlyTotal = cells
      .filter((c) => c.kind === "tenant" || c.kind === "whole")
      .reduce((s, c) => s + c.tenant.rent, 0);

    return { a, cells, occupied, vacant, rooms, flagTone, monthlyTotal };
  });

  const flatsAllClear = cards.filter((c) => c.flagTone === "positive").length;

  return (
    <Card className="property-grid-card" style={{ marginTop: 28 }}>
      <div className="card-head" style={{ marginBottom: 18 }}>
        <h3 style={{ fontSize: 18 }}>{tt("dash.props")}</h3>
        <div className="muted txt-sm">
          {tt("dash.props.sub", { n: data.apartments.length, occ: occupiedRooms, total: totalRooms, paid: paidThisMonth })}
        </div>
        <div className="head-right">
          <Tabs value={view} onChange={setView} tabs={[
            { value: "grid", label: tt("dash.viewGrid") },
            { value: "list", label: tt("dash.viewList") },
          ]} />
          <button className="btn ghost sm" onClick={() => nav("apartments")}>{tt("btn.seeAll")} <Icon name="chevR" size={12} /></button>
        </div>
      </div>

      {view === "grid" ? (
        <div className="carousel-wrap">
          {canPrev && (
            <button className="iconbtn carousel-arrow carousel-arrow-left"
                    onClick={() => scrollBy(-1)} aria-label={tt("a11y.prev") || "Previous"}>
              <Icon name="chevL" size={15} />
            </button>
          )}
          {canNext && (
            <button className="iconbtn carousel-arrow carousel-arrow-right"
                    onClick={() => scrollBy(1)} aria-label={tt("a11y.next") || "Next"}>
              <Icon name="chevR" size={15} />
            </button>
          )}
          <div className="properties-grid mini" ref={carouselRef}>
            {cards.map(({ a, cells, occupied, vacant, rooms, flagTone, monthlyTotal }) => {
              const activeTenants = cells.filter((c) => c.kind === "tenant" || c.kind === "whole").map((c) => c.tenant);
              const summerBks = data.bookings.filter((b) => b.aptId === a.id && b.status === "confirmed" && b.nightly > 0 && b.start >= "2026-06-01" && b.start < "2026-09-01");
              const alertTone = flagTone === "danger" ? "danger" : flagTone === "warn" ? "warn" : null;
              return (
                <div key={a.id} className="property-card mini" onClick={() => nav("apartment", a.id)}>
                  <div className="mini-hero">
                    <AptArchHero aptId={a.id} />
                    <div className="mini-hero-overlay">
                      <span className="mini-hero-chip">
                        {a.type === "rooms" ? `${a.bedrooms} ${tt("ad.rooms") || "rooms"}` : (tt("pg.wholeFlat") || "Whole flat")}
                      </span>
                      {summerBks.length > 0 && (
                        <span className="mini-hero-chip accent">{summerBks.length} summer</span>
                      )}
                    </div>
                  </div>
                  <div className="mini-body">
                    <div className="mini-head">
                      {alertTone && (
                        <span className={`mini-alert mini-alert-${alertTone}`} title={tt("props.alert") || "Needs attention"} aria-label="alert">!</span>
                      )}
                      <span className="mini-name">{a.name}</span>
                      <span onClick={(e) => e.stopPropagation()} style={{ display: "inline-flex", marginLeft: "auto" }}>
                        <Dropdown align="right" trigger={
                          <button className="iconbtn mini-menu" aria-label={tt("props.menu.more") || "Más"}>
                            <Icon name="more" size={13} />
                          </button>
                        }>
                          <MenuItem icon="eye" label={tt("props.menu.open") || "Abrir piso"}
                                    onClick={() => nav("apartment", a.id)} />
                          <MenuItem icon="plus" label={tt("btn.addTenant") || "Añadir inquilino"}
                                    onClick={() => ctx.openAddTenant && ctx.openAddTenant()} />
                          <MenuItem icon="chat" label={tt("btn.messageTenants") || "Mensaje a inquilinos"}
                                    onClick={() => nav("messages")} />
                          <MenuDivider />
                          <MenuItem icon="file" label={tt("props.menu.snapshot") || "Snapshot PDF"}
                                    onClick={() => ctx.showToast && ctx.showToast(`${a.name} snapshot.pdf guardado`)} />
                        </Dropdown>
                      </span>
                    </div>
                    <div className="mini-sub">{a.neighborhood.split(",")[0]}</div>
                    <div className="mini-stats">
                      <div>
                        <div className="mini-stat-lbl">{a.type === "rooms" ? (tt("ad.rooms") || "Rooms") : (tt("st.status") || "Status")}</div>
                        <div className="mini-stat-val num">
                          {a.type === "rooms" ? `${occupied}/${rooms}` : (activeTenants.length ? (tt("st.let") || "Let") : "—")}
                        </div>
                      </div>
                      <div>
                        <div className="mini-stat-lbl">{tt("ad.monthly") || "Monthly"}</div>
                        <div className="mini-stat-val num">{fmtEUR(monthlyTotal)}</div>
                      </div>
                    </div>
                    <div className="mini-tenants">
                      <div style={{ display: "flex" }}>
                        {activeTenants.slice(0, 4).map((tn, i) => (
                          <div key={tn.id} className="avatar sm" data-apt={a.id}
                               style={{ marginLeft: i ? -7 : 0, width: 22, height: 22, fontSize: 9.5 }}
                               title={tn.name}>
                            {initials(tn.name)}
                          </div>
                        ))}
                      </div>
                      <span className="muted txt-xs" style={{ marginLeft: activeTenants.length ? 8 : 0 }}>
                        {activeTenants.length} {activeTenants.length === 1 ? (tt("pg.tenant_one") || "tenant") : (tt("pg.tenant_many") || "tenants")}
                      </span>
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      ) : (
        <PropertyList cards={cards} ctx={ctx} />
      )}
    </Card>
  );
}

// List view — same data, table form
function PropertyList({ cards, ctx }) {
  const { nav, markPaid } = ctx;
  const tt = ctx.tt;
  return (
    <div className="property-list">
      {cards.map(({ a, cells, occupied, vacant, rooms, flagTone, monthlyTotal }) => (
        <div key={a.id} className="property-list-row" onClick={() => nav("apartment", a.id)}>
          <div className="flex center gap-3" style={{ minWidth: 200 }}>
            <span className={`pc-status pc-status-${flagTone}`} aria-hidden="true" />
            <div>
              <div className="b500 ink">{a.name}</div>
              <div className="muted txt-xs">{a.neighborhood.split(",")[0]}</div>
            </div>
          </div>
          <div className="property-list-cells">
            {cells.map((c, i) => {
              if (c.kind === "vacant") {
                return <div key={i} className="pc-mini pc-vacant" title={`${tt("ad.room")} ${c.roomNum} — ${tt("st.vacant")}`}>—<small>H{c.roomNum}</small></div>;
              }
              if (c.kind === "vacant-whole") {
                return <div key={i} className="pc-mini pc-vacant" style={{ flex: 1 }}>— <small>{tt("pg.wholeFlat")}</small></div>;
              }
              if (c.kind === "whole") {
                return <div key={i} className={`pc-mini pc-${c.status}`} style={{ flex: 1 }} title={c.tenant.name}>{shortName(c.tenant.name)} <small>{tt("pg.wholeFlat")}</small></div>;
              }
              return <div key={i} className={`pc-mini pc-${c.status}`} title={c.tenant.name}>{shortName(c.tenant.name)}<small>H{c.roomNum}</small></div>;
            })}
          </div>
          <div className="property-list-foot">
            <span className="muted txt-sm">{occupied}/{rooms}{vacant > 0 && ` · ${vacant} ${tt("pg.vac")}`}</span>
            <span className="num b500" style={{ minWidth: 70, textAlign: "right" }}>{fmtEUR(monthlyTotal)}</span>
            <Icon name="chevR" size={14} className="muted" />
          </div>
        </div>
      ))}
    </div>
  );
}

window.Dashboard = Dashboard;
window.PropertyGrid = PropertyGrid;
window.nightsBetween = nightsBetween;

// ───────────────────────── PENDIENTES (priority feed) ─────────────────────────
// Single section that answers "did rent come in this month?". Merges three
// concerns into one prioritized table: overdue bills + pending bills + high
// maintenance tickets. Each row offers a contextual primary action.
//
// Replaces the previous trio: "Needs attention" card + "Who still owes"
// table + "Recent activity" feed. The Recent Activity feed is killed
// entirely from the dashboard — the AICard already summarizes the day,
// the full timeline lives at /messages and /alertas.
function Pendientes({ ctx }) {
  const { data, nav, markPaid } = ctx;
  const tt = ctx.tt;

  const thisMonthBills = data.bills.filter((b) => b.period === "2026-05" && b.type === "rent");
  const overdueBills = thisMonthBills.filter((b) => b.status === "overdue");
  const pendingBills = thisMonthBills.filter((b) => b.status === "pending");
  const highTickets = data.tickets.filter((t) => t.priority === "high" && t.status !== "resolved");
  const allBills = [...overdueBills, ...pendingBills];
  const total = allBills.length + highTickets.length;

  // Empty state — celebrate the quiet win.
  if (total === 0) {
    return (
      <Card style={{ marginTop: 24 }} id="pendientes">
        <div className="flex center gap-3" style={{ padding: 12 }}>
          <div style={{
            width: 36, height: 36, borderRadius: 10,
            background: "var(--ef-accent-soft)",
            color: "var(--ef-accent-deep)",
            display: "inline-flex", alignItems: "center", justifyContent: "center",
            flex: "0 0 auto",
          }}>
            <Icon name="check" size={18} />
          </div>
          <div className="grow">
            <div className="b500" style={{ fontSize: 14.5 }}>{tt("dash.allClear")}</div>
            <div className="txt-sm muted" style={{ marginTop: 2 }}>{tt("dash.allClear.sub")}</div>
          </div>
        </div>
      </Card>
    );
  }

  return (
    <Card className="flush" style={{ marginTop: 24 }} id="pendientes">
      <div className="card-head" style={{ padding: "16px 22px 12px" }}>
        <h3>{tt("dash.whoOwes")}</h3>
        <div className="muted txt-sm">
          {tt("dash.whoOwes.hint", { overdue: overdueBills.length, pending: pendingBills.length })}
          {highTickets.length > 0 && ` · ${highTickets.length} ${tt("dash.needsAttention").toLowerCase()}`}
        </div>
        <div className="head-right">
          <span className="badge danger"><span className="dot" />{total}</span>
        </div>
      </div>

      {allBills.length > 0 && (
        <table className="table">
          <thead>
            <tr>
              <th>{tt("col.tenant")}</th>
              <th>{tt("col.apartment")}</th>
              <th>{tt("col.bill")}</th>
              <th>{tt("col.due")}</th>
              <th className="num">{tt("col.amount")}</th>
              <th>{tt("col.status")}</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {allBills.map((b) => {
              const tn = b.tenantId && data.byId.tenant(b.tenantId);
              const apt = data.byId.apt(b.aptId);
              return (
                <tr key={b.id}>
                  <td>
                    {tn
                      ? <span className="flex center gap-2" onClick={(e) => { e.stopPropagation(); nav("tenant", tn.id); }}>
                          <div className="avatar sm">{initials(tn.name)}</div>
                          {tn.name} <Flag code={tn.country} />
                        </span>
                      : <span className="muted">{tt("fin.allTenants")}</span>}
                  </td>
                  <td><Link onClick={() => nav("apartment", apt?.id)}>{apt?.name}</Link></td>
                  <td>{b.label}</td>
                  <td className="num muted">{fmtDate(b.dueDate, { short: true })}</td>
                  <td className="num b500">{fmtEUR(b.amount)}</td>
                  <td><StatusBadge status={b.status} /></td>
                  <td style={{ width: 130 }}>
                    <MarkPaidPopover
                      ctx={ctx}
                      bill={b}
                      onConfirm={(method) => markPaid(b.id, { method, amount: fmtEUR(b.amount, { decimals: false }) })}
                    />
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      )}

      {highTickets.length > 0 && (
        <div className="feed" style={{ borderTop: allBills.length > 0 ? "0.5px solid var(--ef-line)" : 0, padding: "8px 12px" }}>
          {highTickets.map((t) => {
            const apt = data.byId.apt(t.aptId);
            const ten = t.tenantId && data.byId.tenant(t.tenantId);
            return (
              <div className="row" key={t.id}>
                <div className="ic danger"><Icon name="wrench" size={14} /></div>
                <div className="body">
                  <p><b>{t.title}</b></p>
                  <small>
                    {apt?.name}
                    {ten ? ` · ${ten.name}` : ""}
                    {" · "}{relTime(t.openedAt)}
                  </small>
                </div>
                <button className="btn sm ghost" onClick={() => nav("maintenance")}>{tt("btn.open")}</button>
              </div>
            );
          })}
        </div>
      )}
    </Card>
  );
}

// ───────────────────────── MARK PAID POPOVER ─────────────────────────
// Replaces the one-click destructive button. Click opens a small
// inline popover with: amount preview (mono), method select
// (Transferencia / Bizum / Efectivo), Cancelar/Confirmar. On confirm
// the parent markPaid handles the actual mutation + undo toast.
function MarkPaidPopover({ ctx, bill, onConfirm }) {
  const tt = ctx.tt;
  const [open, setOpen] = React.useState(false);
  const [method, setMethod] = React.useState("bank");
  const ref = React.useRef();

  React.useEffect(() => {
    if (!open) return;
    const onClick = (e) => { if (!ref.current?.contains(e.target)) setOpen(false); };
    const onKey = (e) => e.key === "Escape" && setOpen(false);
    document.addEventListener("mousedown", onClick);
    document.addEventListener("keydown", onKey);
    return () => {
      document.removeEventListener("mousedown", onClick);
      document.removeEventListener("keydown", onKey);
    };
  }, [open]);

  return (
    <div ref={ref} style={{ position: "relative", display: "inline-block" }}>
      <button className="btn sm" onClick={(e) => { e.stopPropagation(); setOpen((x) => !x); }}>
        {tt("btn.markPaid")}
      </button>
      {open && (
        <div style={{
          position: "absolute", top: "calc(100% + 6px)", right: 0,
          minWidth: 260,
          background: "var(--ef-bg)",
          border: "0.5px solid var(--ef-line)",
          borderRadius: 10,
          boxShadow: "var(--ef-shadow-pop, 0 8px 24px rgba(20,30,60,0.10))",
          padding: 14,
          zIndex: 50,
          display: "flex", flexDirection: "column", gap: 12,
        }}>
          <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
            <span style={{ fontSize: 10.5, letterSpacing: "0.08em", textTransform: "uppercase", color: "var(--ef-muted)" }}>
              {tt("mp.amount")}
            </span>
            <span className="num" style={{
              fontFamily: "'JetBrains Mono', ui-monospace, monospace",
              fontSize: 22, fontWeight: 500, letterSpacing: "-0.015em",
              fontVariantNumeric: "tabular-nums",
              color: "var(--ef-ink)",
            }}>
              {fmtEUR(bill.amount)}
            </span>
          </div>

          <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
            <span style={{ fontSize: 10.5, letterSpacing: "0.08em", textTransform: "uppercase", color: "var(--ef-muted)" }}>
              {tt("mp.method")}
            </span>
            <div style={{ display: "flex", gap: 6 }}>
              {["bank", "bizum", "cash"].map((m) => (
                <button
                  key={m}
                  type="button"
                  onClick={() => setMethod(m)}
                  className="btn sm"
                  aria-pressed={method === m}
                  style={{
                    flex: 1,
                    background: method === m ? "var(--ef-primary)" : "var(--ef-bg-soft)",
                    color: method === m ? "var(--ef-primary-ink)" : "var(--ef-ink-2)",
                    border: "0.5px solid var(--ef-line)",
                    fontSize: 12,
                    fontWeight: 500,
                    padding: "6px 8px",
                  }}
                >
                  {tt(`mp.method.${m}`)}
                </button>
              ))}
            </div>
          </div>

          <div style={{ display: "flex", gap: 8, justifyContent: "flex-end", marginTop: 2 }}>
            <button className="btn sm ghost" onClick={() => setOpen(false)}>
              {tt("mp.cancel")}
            </button>
            <button className="btn sm primary" onClick={() => { setOpen(false); onConfirm && onConfirm(method); }}>
              <Icon name="check" size={12} /> {tt("mp.confirm")}
            </button>
          </div>
        </div>
      )}
    </div>
  );
}

window.Pendientes = Pendientes;
window.MarkPaidPopover = MarkPaidPopover;

// ───────────────────────── AI moat hero ─────────────────────────
// Sits above the KPI strip on /preview/E. Answers "what did my AI agent
// do for me today?" with 3-5 concrete actions derived from the overlay
// data so the numbers feel real, not faked. Castellano copy by default.
//
// Composition (left → right):
//   • Lead: agent avatar (spark) + greeting headline + last-run timestamp
//   • Chips: 4 dotted action lines (invoices read, payments detected,
//     anomalies, drive synced) — green dot for success, amber for warn
//   • Action: primary CTA "Hablar con Arco" that expands the chat rail
//
// No gradient, no glow, no big "AI" letters. Restrained accent: green
// shows up only on the chip dots; everything else is --ef-ink* / --ef-muted.
function AICard({ ctx }) {
  const { tt, data, toggleChat } = ctx;

  // Derive realistic counts from the visible data so the hero never lies.
  // Last 24h is an approximation: we use status + AI source heuristics.
  const todayISO = ArcoData.ISO(ArcoData.today);
  const invoicesRead = data.bills.filter((b) => {
    if (!b.label) return false;
    const l = b.label.toLowerCase();
    return l.includes("luz") || l.includes("agua") || l.includes("internet")
        || l.includes("digi") || l.includes("iberdrola") || l.includes("aqualia")
        || l.includes("finetwork") || l.includes("totalenergies");
  }).length;
  const paymentsDetected = data.bills.filter((b) => b.status === "paid").length;
  const anomalies = data.bills.filter((b) => b.status === "overdue").length;
  const lastRun = "06:24";

  // Greeting headline number = sum of three realistic action counts.
  const totalActions = invoicesRead + paymentsDetected + (anomalies > 0 ? 1 : 0) + 1; // +1 for Drive

  // Compose the headline split so the number stays in a <b> for mono styling.
  const headlineKey = totalActions > 0 ? "ai.headline" : "ai.empty";
  const headlineStr = tt(headlineKey, { n: totalActions });
  // Wrap the digit substring in <b> for the mono treatment via CSS.
  const headlineParts = headlineStr.replace(
    String(totalActions),
    `<b>${totalActions}</b>`
  );

  const lastRunKey = anomalies > 0 ? "ai.lastRunWarn" : "ai.lastRun";
  const lastRunStr = tt(lastRunKey, { time: lastRun, n: anomalies });

  // Empty state — quiet night.
  if (totalActions <= 1) {
    return (
      <div className="ai-card" role="region" aria-label={tt("chat.title")}>
        <div className="ai-card-lead">
          <span className="ai-card-avatar" aria-hidden>
            <Icon name="spark" size={16} />
          </span>
          <div className="ai-card-greeting">
            <div className="head">{tt("ai.empty")}</div>
            <div className="sub">{tt("ai.lastRun", { time: lastRun })}</div>
          </div>
        </div>
        <div />
        <div className="ai-card-action">
          <button className="ai-card-cta" onClick={toggleChat}>
            <Icon name="spark" size={13} /> {tt("ai.cta")}
          </button>
        </div>
      </div>
    );
  }

  return (
    <div className="ai-card" role="region" aria-label={tt("chat.title")}>
      <div className="ai-card-lead">
        <span className="ai-card-avatar" aria-hidden>
          <Icon name="spark" size={16} />
        </span>
        <div className="ai-card-greeting">
          <div className="head" dangerouslySetInnerHTML={{ __html: headlineParts }} />
          <div className="sub">{lastRunStr}</div>
        </div>
      </div>

      <div className="ai-card-chips">
        {invoicesRead > 0 && (
          <span className="ai-chip">
            <span className="dot" />
            <span dangerouslySetInnerHTML={{ __html:
              tt("ai.chip.bills", { n: invoicesRead })
                .replace(String(invoicesRead), `<span class="num">${invoicesRead}</span>`)
            }} />
          </span>
        )}
        {paymentsDetected > 0 && (
          <span className="ai-chip">
            <span className="dot" />
            <span dangerouslySetInnerHTML={{ __html:
              tt("ai.chip.payments", { n: paymentsDetected })
                .replace(String(paymentsDetected), `<span class="num">${paymentsDetected}</span>`)
            }} />
          </span>
        )}
        {anomalies > 0 && (
          <span className="ai-chip warn" role="button"
                onClick={() => ctx.nav("maintenance")}
                tabIndex={0}>
            <span className="dot" />
            <span dangerouslySetInnerHTML={{ __html:
              tt(anomalies === 1 ? "ai.chip.anomaly" : "ai.chip.anomalies", { n: anomalies })
                .replace(String(anomalies), `<span class="num">${anomalies}</span>`)
            }} />
          </span>
        )}
        <span className="ai-chip">
          <span className="dot" />
          <span>{tt("ai.chip.drive")}</span>
        </span>
      </div>

      <div className="ai-card-action">
        <button className="ai-card-cta" onClick={toggleChat}>
          <Icon name="spark" size={13} /> {tt("ai.cta")}
        </button>
      </div>
    </div>
  );
}

window.AICard = AICard;
