/* ==================================================================
 * app.js — Interface e lógica de negócio
 * ================================================================== */

/* ------------------------- Helpers ------------------------- */
const $ = (sel, root = document) => root.querySelector(sel);
const $$ = (sel, root = document) => [...root.querySelectorAll(sel)];

function money(n) {
  const s = Store.getSettings();
  const v = Number(n || 0);
  return v.toLocaleString("pt-PT", { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + " " + s.currency;
}
function num(n, d = 0) {
  return Number(n || 0).toLocaleString("pt-PT", { minimumFractionDigits: d, maximumFractionDigits: d });
}
function fmtDate(iso) {
  if (!iso) return "—";
  const d = new Date(iso);
  return d.toLocaleDateString("pt-PT");
}
function daysUntil(iso) {
  if (!iso) return Infinity;
  const d = new Date(iso);
  const now = new Date();
  now.setHours(0, 0, 0, 0);
  return Math.round((d - now) / 86400000);
}
function hoursMin(minutes) {
  const h = Math.floor(minutes / 60);
  const m = Math.round(minutes % 60);
  return (h ? h + "h " : "") + m + "min";
}
function esc(s) {
  return String(s ?? "").replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" }[c]));
}

function toast(msg, isErr = false) {
  const t = $("#toast");
  t.textContent = msg;
  t.className = "toast show" + (isErr ? " err" : "");
  setTimeout(() => (t.className = "toast"), 3200);
}

/* ------------------------- Modal ------------------------- */
function openModal(title, bodyHTML, buttons = []) {
  $("#modal-title").textContent = title;
  $("#modal-body").innerHTML = bodyHTML;
  const foot = $("#modal-foot");
  foot.innerHTML = "";
  buttons.forEach((b) => {
    const btn = document.createElement("button");
    btn.className = "btn " + (b.class || "");
    btn.textContent = b.label;
    btn.onclick = b.onClick;
    if (b.id) btn.id = b.id;
    foot.appendChild(btn);
  });
  $("#modal-overlay").classList.add("open");
}
function closeModal() {
  $("#modal-overlay").classList.remove("open");
}
$("#modal-close").onclick = closeModal;
$("#modal-overlay").onclick = (e) => {
  if (e.target === $("#modal-overlay")) closeModal();
};

/* ------------------------- Regras de negócio ------------------------- */
const STATUS_BADGE = {
  planeada: "blue",
  "em curso": "amber",
  concluída: "green",
  cancelada: "gray",
  disponível: "green",
  "em viagem": "amber",
  manutenção: "red",
  ativo: "green",
  inativo: "gray",
};
function badge(text) {
  return `<span class="badge ${STATUS_BADGE[text] || "gray"}">${esc(text)}</span>`;
}

function tripCost(trip) {
  const s = Store.getSettings();
  const truck = Store.get("trucks", trip.truckId);
  const consumption = truck?.fuelConsumptionLper100 || 30;
  const fuel = (Number(trip.distanceKm || 0) / 100) * consumption * s.fuelPricePerL;
  const driver = (Number(trip.durationMin || 0) / 60) * s.driverCostPerHour;
  const tolls = Number(trip.tollCost || 0);
  const total = fuel + driver + tolls;
  const price = Number(trip.priceCharged || 0);
  const margin = price - total;
  const costPerKm = trip.distanceKm ? total / trip.distanceKm : 0;
  return { fuel, driver, tolls, total, price, margin, costPerKm };
}

// Regulamento (UE) 561/2006 — tempo de condução diário
function drivingWarning(durationMin) {
  const s = Store.getSettings();
  const maxMin = s.maxDailyDrivingHours * 60;
  if (durationMin > maxMin) {
    const days = Math.ceil(durationMin / maxMin);
    return `Duração (${hoursMin(durationMin)}) excede o limite diário de condução de ${s.maxDailyDrivingHours}h. Prevê ~${days} dias / descansos obrigatórios (Reg. UE 561/2006).`;
  }
  if (durationMin > 4.5 * 60) {
    return `Condução superior a 4h30 — é obrigatória uma pausa de 45min (Reg. UE 561/2006).`;
  }
  return null;
}

function computeAlerts() {
  const alerts = [];
  Store.list("trucks").forEach((t) => {
    const di = daysUntil(t.inspectionDue);
    if (di <= 30) alerts.push({ level: di < 0 ? "danger" : "warn", ico: "🔧", msg: `Camião ${t.plate}: inspeção ${di < 0 ? "vencida há " + -di + " dias" : "em " + di + " dias"} (${fmtDate(t.inspectionDue)})` });
    const ds = daysUntil(t.insuranceDue);
    if (ds <= 30) alerts.push({ level: ds < 0 ? "danger" : "warn", ico: "🛡️", msg: `Camião ${t.plate}: seguro ${ds < 0 ? "vencido" : "expira em " + ds + " dias"} (${fmtDate(t.insuranceDue)})` });
  });
  Store.list("drivers").forEach((d) => {
    const dl = daysUntil(d.licenseExpiry);
    if (dl <= 30) alerts.push({ level: dl < 0 ? "danger" : "warn", ico: "🪪", msg: `Motorista ${d.name}: carta ${dl < 0 ? "caducada" : "caduca em " + dl + " dias"} (${fmtDate(d.licenseExpiry)})` });
  });
  Store.list("trips").filter((t) => t.status !== "concluída" && t.status !== "cancelada").forEach((t) => {
    const w = drivingWarning(t.durationMin || 0);
    if (w) alerts.push({ level: "info", ico: "⏱️", msg: `Viagem ${t.origin?.name} → ${t.destination?.name}: ${w}` });
  });
  return alerts;
}

function isThisMonth(iso) {
  if (!iso) return false;
  const d = new Date(iso);
  const n = new Date();
  return d.getMonth() === n.getMonth() && d.getFullYear() === n.getFullYear();
}

/* ------------------------- Router ------------------------- */
const views = {};
let mapInstance = null;
let routeLayer = null;

function navigate(view) {
  $$(".nav-item").forEach((n) => n.classList.toggle("active", n.dataset.view === view));
  if (mapInstance && view !== "trips") {
    mapInstance.remove();
    mapInstance = null;
  }
  (views[view] || views.dashboard)();
}
$$(".nav-item").forEach((n) => (n.onclick = () => navigate(n.dataset.view)));

/* ==================================================================
 * VISTA: Dashboard
 * ================================================================== */
views.dashboard = function () {
  const trucks = Store.list("trucks");
  const drivers = Store.list("drivers");
  const trips = Store.list("trips");
  const monthTrips = trips.filter((t) => isThisMonth(t.plannedDate) && t.status !== "cancelada");

  let revenue = 0, cost = 0, km = 0;
  monthTrips.forEach((t) => {
    const c = tripCost(t);
    revenue += c.price;
    cost += c.total;
    km += Number(t.distanceKm || 0);
  });
  const profit = revenue - cost;
  const inTransit = trips.filter((t) => t.status === "em curso").length;
  const utilization = trucks.length ? Math.round((inTransit / trucks.length) * 100) : 0;
  const alerts = computeAlerts();

  const alertsHTML = alerts.length
    ? `<div class="alert-list">${alerts.map((a) => `<div class="alert-item ${a.level}"><span class="ico">${a.ico}</span> ${esc(a.msg)}</div>`).join("")}</div>`
    : `<div class="empty"><div class="big">✅</div>Sem alertas. Tudo em ordem.</div>`;

  const recent = [...trips].sort((a, b) => (b.plannedDate || "").localeCompare(a.plannedDate || "")).slice(0, 6);

  $("#main").innerHTML = `
    <div class="page-head">
      <div><h1>Dashboard</h1><p>Visão geral do mês de ${new Date().toLocaleDateString("pt-PT", { month: "long", year: "numeric" })}</p></div>
      <button class="btn" onclick="navigate('trips')">＋ Nova viagem</button>
    </div>

    <div class="grid kpis">
      ${kpi("Receita do mês", money(revenue))}
      ${kpi("Custos do mês", money(cost))}
      ${kpi("Lucro do mês", money(profit), profit >= 0 ? "ok" : "danger")}
      ${kpi("Km planeados", num(km) + " km")}
      ${kpi("Viagens do mês", monthTrips.length)}
      ${kpi("Frota / motoristas", trucks.length + " / " + drivers.length)}
      ${kpi("Camiões em viagem", inTransit)}
      ${kpi("Utilização da frota", utilization + "%")}
    </div>

    <div class="grid cols-2" style="margin-top:18px">
      <div class="card">
        <h3>⚠️ Alertas operacionais</h3>
        ${alertsHTML}
      </div>
      <div class="card">
        <h3>🕑 Viagens recentes</h3>
        ${recent.length ? `<div class="table-wrap"><table>
          <thead><tr><th>Rota</th><th>Data</th><th>Estado</th><th>Margem</th></tr></thead>
          <tbody>${recent.map((t) => {
            const c = tripCost(t);
            return `<tr>
              <td>${esc(t.origin?.name || "?")} → ${esc(t.destination?.name || "?")}</td>
              <td>${fmtDate(t.plannedDate)}</td>
              <td>${badge(t.status)}</td>
              <td class="${c.margin >= 0 ? "pos" : "neg"}">${money(c.margin)}</td>
            </tr>`;
          }).join("")}</tbody></table></div>` : `<div class="empty">Sem viagens ainda.</div>`}
      </div>
    </div>
  `;
};

function kpi(label, value, cls = "") {
  return `<div class="card kpi"><span class="label">${label}</span><span class="value ${cls}">${value}</span></div>`;
}

/* ==================================================================
 * VISTA: Viagens & Rotas (com mapa)
 * ================================================================== */
views.trips = function () {
  const trips = Store.list("trips");
  $("#main").innerHTML = `
    <div class="page-head">
      <div><h1>Viagens & Rotas</h1><p>Planeamento de fretes e cálculo de trajetos para veículos pesados</p></div>
      <button class="btn" id="new-trip">＋ Nova viagem</button>
    </div>
    <div class="card" style="margin-bottom:18px"><div id="map"></div><div class="mini-note" id="map-note">Clica numa viagem para ver o trajeto no mapa.</div></div>
    <div class="card">
      <h3>Viagens (${trips.length})</h3>
      ${trips.length ? tripsTable(trips) : `<div class="empty"><div class="big">🗺️</div>Sem viagens. Cria a primeira frete.</div>`}
    </div>
  `;

  // init map
  setTimeout(() => {
    if (mapInstance) mapInstance.remove();
    mapInstance = L.map("map").setView([39.6, -8.0], 6);
    L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
      attribution: "© OpenStreetMap",
      maxZoom: 19,
    }).addTo(mapInstance);
    // desenha todas as viagens com geometria
    trips.forEach((t) => t.geometry && drawTrip(t, false));
    if (trips.some((t) => t.geometry)) fitAllTrips(trips);
  }, 50);

  $("#new-trip").onclick = () => openTripModal();
};

function tripsTable(trips) {
  return `<div class="table-wrap"><table>
    <thead><tr><th>Rota</th><th>Carga</th><th>Camião</th><th>Motorista</th><th>Distância</th><th>Tempo</th><th>Margem</th><th>Estado</th><th></th></tr></thead>
    <tbody>${trips.map((t) => {
      const c = tripCost(t);
      const truck = Store.get("trucks", t.truckId);
      const driver = Store.get("drivers", t.driverId);
      return `<tr style="cursor:pointer" onclick="focusTrip('${t.id}')">
        <td><strong>${esc(t.origin?.name || "?")}</strong> → <strong>${esc(t.destination?.name || "?")}</strong></td>
        <td>${esc(t.cargoDesc || "—")}<br><span class="hint">${num(t.weightKg)} kg</span></td>
        <td>${truck ? esc(truck.plate) : "—"}</td>
        <td>${driver ? esc(driver.name) : "—"}</td>
        <td>${num(t.distanceKm, 1)} km${t.estimated ? ' <span class="hint">(est.)</span>' : ""}</td>
        <td>${hoursMin(t.durationMin || 0)}</td>
        <td class="${c.margin >= 0 ? "pos" : "neg"}">${money(c.margin)}</td>
        <td>${badge(t.status)}</td>
        <td onclick="event.stopPropagation()"><div class="row-actions">
          <button class="icon-btn" title="Editar" onclick="openTripModal('${t.id}')">✏️</button>
          <button class="icon-btn" title="Eliminar" onclick="delTrip('${t.id}')">🗑️</button>
        </div></td>
      </tr>`;
    }).join("")}</tbody></table></div>`;
}

const TRIP_COLORS = ["#2563eb", "#16a34a", "#d97706", "#dc2626", "#7c3aed", "#0891b2"];
const tripLayers = {};

function drawTrip(trip, focus = true) {
  if (!mapInstance || !trip.geometry) return;
  if (tripLayers[trip.id]) mapInstance.removeLayer(tripLayers[trip.id]);
  const color = TRIP_COLORS[[...Store.list("trips")].findIndex((t) => t.id === trip.id) % TRIP_COLORS.length];
  const grp = L.layerGroup();
  L.polyline(trip.geometry, { color, weight: 5, opacity: 0.85 }).addTo(grp);
  const o = trip.origin, d = trip.destination;
  if (o) L.marker([o.lat, o.lon]).addTo(grp).bindPopup(`<b>Origem:</b> ${esc(o.name)}`);
  if (d) L.marker([d.lat, d.lon]).addTo(grp).bindPopup(`<b>Destino:</b> ${esc(d.name)}`);
  grp.addTo(mapInstance);
  tripLayers[trip.id] = grp;
  if (focus) mapInstance.fitBounds(L.polyline(trip.geometry).getBounds(), { padding: [40, 40] });
}

function fitAllTrips(trips) {
  const pts = [];
  trips.forEach((t) => t.geometry && t.geometry.forEach((p) => pts.push(p)));
  if (pts.length) mapInstance.fitBounds(L.latLngBounds(pts), { padding: [40, 40] });
}

window.focusTrip = function (id) {
  const t = Store.get("trips", id);
  if (t?.geometry) {
    drawTrip(t, true);
    $("#map-note").textContent = `Trajeto: ${t.origin?.name} → ${t.destination?.name} · ${num(t.distanceKm, 1)} km · ${hoursMin(t.durationMin || 0)}`;
  } else {
    toast("Esta viagem ainda não tem trajeto calculado.", true);
  }
};

window.delTrip = function (id) {
  if (confirm("Eliminar esta viagem?")) {
    Store.remove("trips", id);
    if (tripLayers[id] && mapInstance) mapInstance.removeLayer(tripLayers[id]);
    navigate("trips");
    toast("Viagem eliminada.");
  }
};

// --- Modal de viagem (criar/editar) ---
window.openTripModal = function (id) {
  const trip = id ? Store.get("trips", id) : {};
  const trucks = Store.list("trucks");
  const drivers = Store.list("drivers");
  const truckOpts = `<option value="">— selecionar —</option>` + trucks.map((t) => `<option value="${t.id}" ${trip.truckId === t.id ? "selected" : ""}>${esc(t.plate)} · ${esc(t.brand)} ${esc(t.model)}</option>`).join("");
  const driverOpts = `<option value="">— selecionar —</option>` + drivers.map((d) => `<option value="${d.id}" ${trip.driverId === d.id ? "selected" : ""}>${esc(d.name)}</option>`).join("");
  const statuses = ["planeada", "em curso", "concluída", "cancelada"];

  openModal(
    id ? "Editar viagem" : "Nova viagem",
    `
    <div class="form-row">
      <label class="field">Origem <span class="req">*</span>
        <input id="f-origin" placeholder="Ex: Lisboa" value="${esc(trip.origin?.name || "")}" />
      </label>
      <label class="field">Destino <span class="req">*</span>
        <input id="f-dest" placeholder="Ex: Porto" value="${esc(trip.destination?.name || "")}" />
      </label>
    </div>
    <div class="form-row">
      <label class="field">Descrição da carga
        <input id="f-cargo" value="${esc(trip.cargoDesc || "")}" placeholder="Ex: Material de construção" />
      </label>
      <label class="field">Peso da carga (kg)
        <input id="f-weight" type="number" min="0" value="${trip.weightKg || ""}" />
      </label>
    </div>
    <div class="form-row-3">
      <label class="field">Camião ${truckOpts.includes("selected") ? "" : ""}
        <select id="f-truck">${truckOpts}</select>
      </label>
      <label class="field">Motorista
        <select id="f-driver">${driverOpts}</select>
      </label>
      <label class="field">Data prevista
        <input id="f-date" type="date" value="${trip.plannedDate || ""}" />
      </label>
    </div>
    <div class="form-row-3">
      <label class="field">Preço cobrado (€)
        <input id="f-price" type="number" min="0" step="0.01" value="${trip.priceCharged || ""}" />
      </label>
      <label class="field">Portagens (€)
        <input id="f-tolls" type="number" min="0" step="0.01" value="${trip.tollCost || ""}" />
      </label>
      <label class="field">Estado
        <select id="f-status">${statuses.map((s) => `<option ${trip.status === s ? "selected" : ""}>${s}</option>`).join("")}</select>
      </label>
    </div>
    <button class="btn ghost" id="f-calc" style="margin-bottom:12px">📍 Calcular trajeto e custos</button>
    <div id="f-result"></div>
    `,
    [
      { label: "Cancelar", class: "ghost", onClick: closeModal },
      { label: id ? "Guardar" : "Criar viagem", onClick: () => saveTrip(id) },
    ]
  );

  // guarda o cálculo temporário no botão
  let calc = { distanceKm: trip.distanceKm, durationMin: trip.durationMin, geometry: trip.geometry, origin: trip.origin, destination: trip.destination, estimated: trip.estimated };
  window._tripCalc = calc;

  $("#f-calc").onclick = async () => {
    const originQ = $("#f-origin").value.trim();
    const destQ = $("#f-dest").value.trim();
    if (!originQ || !destQ) return toast("Preenche origem e destino.", true);
    $("#f-calc").disabled = true;
    $("#f-calc").textContent = "A calcular…";
    try {
      const [o, d] = await Promise.all([Geo.geocode(originQ), Geo.geocode(destQ)]);
      const truck = $("#f-truck").value ? Store.get("trucks", $("#f-truck").value) : null;
      const r = await Geo.route([o, d], truck);
      window._tripCalc = { ...r, origin: o, destination: d };
      renderTripResult(window._tripCalc, truck);
    } catch (e) {
      toast(e.message, true);
    } finally {
      $("#f-calc").disabled = false;
      $("#f-calc").textContent = "📍 Recalcular trajeto e custos";
    }
  };

  if (trip.geometry || trip.distanceKm) {
    renderTripResult(calc, trip.truckId ? Store.get("trucks", trip.truckId) : null);
  }
};

function renderTripResult(calc, truck) {
  const fake = {
    distanceKm: calc.distanceKm, durationMin: calc.durationMin,
    truckId: truck?.id, tollCost: Number($("#f-tolls")?.value || 0),
    priceCharged: Number($("#f-price")?.value || 0),
  };
  const c = tripCost(fake);
  const warn = drivingWarning(calc.durationMin || 0);
  $("#f-result").innerHTML = `
    <div class="card" style="box-shadow:none;background:#f8fafc">
      <div class="summary-line"><span>Distância</span><strong>${num(calc.distanceKm, 1)} km ${calc.estimated ? '<span class="hint">(estimativa — sem chave ORS)</span>' : ""}</strong></div>
      <div class="summary-line"><span>Tempo de condução</span><strong>${hoursMin(calc.durationMin || 0)}</strong></div>
      <div class="summary-line"><span>Combustível (${truck ? truck.fuelConsumptionLper100 : 30} L/100km)</span><span>${money(c.fuel)}</span></div>
      <div class="summary-line"><span>Motorista</span><span>${money(c.driver)}</span></div>
      <div class="summary-line"><span>Portagens</span><span>${money(c.tolls)}</span></div>
      <div class="summary-line"><span>Custo total</span><strong>${money(c.total)}</strong></div>
      <div class="summary-line"><span>Custo por km</span><span>${money(c.costPerKm)}</span></div>
      <div class="summary-line"><span>Margem estimada</span><strong class="${c.margin >= 0 ? "pos" : "neg"}">${money(c.margin)}</strong></div>
      ${warn ? `<div class="alert-item info" style="margin-top:10px"><span class="ico">⏱️</span> ${esc(warn)}</div>` : ""}
    </div>`;
}

function saveTrip(id) {
  const origin = $("#f-origin").value.trim();
  const dest = $("#f-dest").value.trim();
  if (!origin || !dest) return toast("Origem e destino são obrigatórios.", true);
  const calc = window._tripCalc || {};

  const trip = {
    id,
    cargoDesc: $("#f-cargo").value.trim(),
    weightKg: Number($("#f-weight").value || 0),
    origin: calc.origin || { name: origin, lat: null, lon: null },
    destination: calc.destination || { name: dest, lat: null, lon: null },
    waypoints: [],
    truckId: $("#f-truck").value || null,
    driverId: $("#f-driver").value || null,
    plannedDate: $("#f-date").value || null,
    priceCharged: Number($("#f-price").value || 0),
    tollCost: Number($("#f-tolls").value || 0),
    status: $("#f-status").value,
    distanceKm: calc.distanceKm || 0,
    durationMin: calc.durationMin || 0,
    geometry: calc.geometry || null,
    estimated: !!calc.estimated,
  };

  // Deteção de conflitos (mesmo camião/motorista na mesma data)
  const conflicts = Store.list("trips").filter((t) =>
    t.id !== id && t.plannedDate && t.plannedDate === trip.plannedDate &&
    t.status !== "concluída" && t.status !== "cancelada" &&
    ((trip.truckId && t.truckId === trip.truckId) || (trip.driverId && t.driverId === trip.driverId))
  );
  if (conflicts.length && !confirm(`Atenção: o camião ou motorista já tem ${conflicts.length} viagem(ns) marcada(s) para ${fmtDate(trip.plannedDate)}. Guardar mesmo assim?`)) {
    return;
  }

  Store.upsert("trips", trip);
  closeModal();
  navigate("trips");
  toast(id ? "Viagem atualizada." : "Viagem criada.");
}

/* ==================================================================
 * VISTA: Camiões
 * ================================================================== */
views.trucks = function () {
  const trucks = Store.list("trucks");
  $("#main").innerHTML = `
    <div class="page-head">
      <div><h1>Camiões</h1><p>Frota, capacidades e prazos legais</p></div>
      <button class="btn" onclick="openTruckModal()">＋ Adicionar camião</button>
    </div>
    <div class="card">
      ${trucks.length ? `<div class="table-wrap"><table>
        <thead><tr><th>Matrícula</th><th>Veículo</th><th>Capacidade</th><th>Consumo</th><th>Inspeção</th><th>Seguro</th><th>Estado</th><th></th></tr></thead>
        <tbody>${trucks.map((t) => {
          const di = daysUntil(t.inspectionDue), ds = daysUntil(t.insuranceDue);
          return `<tr>
            <td><strong>${esc(t.plate)}</strong></td>
            <td>${esc(t.brand)} ${esc(t.model)}<br><span class="hint">${num(t.heightM,2)}m alt · ${num(t.lengthM,1)}m compr</span></td>
            <td>${num(t.maxWeightKg)} kg</td>
            <td>${num(t.fuelConsumptionLper100)} L/100km</td>
            <td>${fmtDate(t.inspectionDue)} ${di <= 30 ? `<span class="badge ${di<0?'red':'amber'}">${di<0?'vencida':di+'d'}</span>` : ""}</td>
            <td>${fmtDate(t.insuranceDue)} ${ds <= 30 ? `<span class="badge ${ds<0?'red':'amber'}">${ds<0?'vencido':ds+'d'}</span>` : ""}</td>
            <td>${badge(t.status)}</td>
            <td><div class="row-actions">
              <button class="icon-btn" onclick="openTruckModal('${t.id}')">✏️</button>
              <button class="icon-btn" onclick="delEntity('trucks','${t.id}','trucks')">🗑️</button>
            </div></td>
          </tr>`;
        }).join("")}</tbody></table></div>` : `<div class="empty"><div class="big">🚛</div>Sem camiões. Adiciona o primeiro.</div>`}
    </div>
  `;
};

window.openTruckModal = function (id) {
  const t = id ? Store.get("trucks", id) : {};
  const statuses = ["disponível", "em viagem", "manutenção"];
  openModal(id ? "Editar camião" : "Novo camião", `
    <div class="form-row">
      <label class="field">Matrícula <span class="req">*</span><input id="t-plate" value="${esc(t.plate||"")}" /></label>
      <label class="field">Estado<select id="t-status">${statuses.map(s=>`<option ${t.status===s?"selected":""}>${s}</option>`).join("")}</select></label>
    </div>
    <div class="form-row">
      <label class="field">Marca<input id="t-brand" value="${esc(t.brand||"")}" /></label>
      <label class="field">Modelo<input id="t-model" value="${esc(t.model||"")}" /></label>
    </div>
    <div class="form-row-3">
      <label class="field">Peso máx. (kg)<input id="t-maxw" type="number" value="${t.maxWeightKg||""}" /></label>
      <label class="field">Tara (kg)<input id="t-tare" type="number" value="${t.tareKg||""}" /></label>
      <label class="field">Consumo (L/100km)<input id="t-fuel" type="number" step="0.1" value="${t.fuelConsumptionLper100||""}" /></label>
    </div>
    <div class="form-row-3">
      <label class="field">Altura (m)<input id="t-h" type="number" step="0.01" value="${t.heightM||""}" /></label>
      <label class="field">Largura (m)<input id="t-w" type="number" step="0.01" value="${t.widthM||""}" /></label>
      <label class="field">Comprimento (m)<input id="t-l" type="number" step="0.1" value="${t.lengthM||""}" /></label>
    </div>
    <div class="form-row">
      <label class="field">Próxima inspeção<input id="t-insp" type="date" value="${t.inspectionDue||""}" /></label>
      <label class="field">Validade do seguro<input id="t-ins" type="date" value="${t.insuranceDue||""}" /></label>
    </div>
    <p class="hint">As dimensões e o peso são usados no cálculo de rotas para pesados (evitam estradas com restrições).</p>
  `, [
    { label: "Cancelar", class: "ghost", onClick: closeModal },
    { label: "Guardar", onClick: () => {
      const plate = $("#t-plate").value.trim();
      if (!plate) return toast("A matrícula é obrigatória.", true);
      Store.upsert("trucks", {
        id, plate, brand: $("#t-brand").value.trim(), model: $("#t-model").value.trim(),
        maxWeightKg: Number($("#t-maxw").value||0), tareKg: Number($("#t-tare").value||0),
        fuelConsumptionLper100: Number($("#t-fuel").value||0),
        heightM: Number($("#t-h").value||0), widthM: Number($("#t-w").value||0), lengthM: Number($("#t-l").value||0),
        inspectionDue: $("#t-insp").value||null, insuranceDue: $("#t-ins").value||null,
        status: $("#t-status").value,
      });
      closeModal(); navigate("trucks"); toast("Camião guardado.");
    } },
  ]);
};

/* ==================================================================
 * VISTA: Motoristas
 * ================================================================== */
views.drivers = function () {
  const drivers = Store.list("drivers");
  $("#main").innerHTML = `
    <div class="page-head">
      <div><h1>Motoristas</h1><p>Equipa, cartas de condução e contactos</p></div>
      <button class="btn" onclick="openDriverModal()">＋ Adicionar motorista</button>
    </div>
    <div class="card">
      ${drivers.length ? `<div class="table-wrap"><table>
        <thead><tr><th>Nome</th><th>Nº carta</th><th>Categorias</th><th>Validade carta</th><th>Telefone</th><th>Estado</th><th></th></tr></thead>
        <tbody>${drivers.map((d) => {
          const dl = daysUntil(d.licenseExpiry);
          return `<tr>
            <td><strong>${esc(d.name)}</strong></td>
            <td>${esc(d.licenseNumber||"—")}</td>
            <td>${esc(d.licenseCategories||"—")}</td>
            <td>${fmtDate(d.licenseExpiry)} ${dl<=30?`<span class="badge ${dl<0?'red':'amber'}">${dl<0?'caducada':dl+'d'}</span>`:""}</td>
            <td>${esc(d.phone||"—")}</td>
            <td>${badge(d.status)}</td>
            <td><div class="row-actions">
              <button class="icon-btn" onclick="openDriverModal('${d.id}')">✏️</button>
              <button class="icon-btn" onclick="delEntity('drivers','${d.id}','drivers')">🗑️</button>
            </div></td>
          </tr>`;
        }).join("")}</tbody></table></div>` : `<div class="empty"><div class="big">👷</div>Sem motoristas registados.</div>`}
    </div>
  `;
};

window.openDriverModal = function (id) {
  const d = id ? Store.get("drivers", id) : {};
  const statuses = ["ativo", "inativo"];
  openModal(id ? "Editar motorista" : "Novo motorista", `
    <label class="field">Nome <span class="req">*</span><input id="d-name" value="${esc(d.name||"")}" /></label>
    <div class="form-row">
      <label class="field">Nº da carta<input id="d-lic" value="${esc(d.licenseNumber||"")}" /></label>
      <label class="field">Categorias<input id="d-cat" value="${esc(d.licenseCategories||"C+E")}" placeholder="C, C+E, ..." /></label>
    </div>
    <div class="form-row-3">
      <label class="field">Validade da carta<input id="d-exp" type="date" value="${d.licenseExpiry||""}" /></label>
      <label class="field">Telefone<input id="d-phone" value="${esc(d.phone||"")}" /></label>
      <label class="field">Estado<select id="d-status">${statuses.map(s=>`<option ${d.status===s?"selected":""}>${s}</option>`).join("")}</select></label>
    </div>
  `, [
    { label: "Cancelar", class: "ghost", onClick: closeModal },
    { label: "Guardar", onClick: () => {
      const name = $("#d-name").value.trim();
      if (!name) return toast("O nome é obrigatório.", true);
      Store.upsert("drivers", {
        id, name, licenseNumber: $("#d-lic").value.trim(), licenseCategories: $("#d-cat").value.trim(),
        licenseExpiry: $("#d-exp").value||null, phone: $("#d-phone").value.trim(), status: $("#d-status").value,
      });
      closeModal(); navigate("drivers"); toast("Motorista guardado.");
    } },
  ]);
};

/* ==================================================================
 * VISTA: Financeiro
 * ================================================================== */
views.finance = function () {
  const trips = Store.list("trips").filter((t) => t.status !== "cancelada");
  const expenses = Store.list("expenses");

  let revenue = 0, opCost = 0;
  trips.forEach((t) => { const c = tripCost(t); revenue += c.price; opCost += c.total; });
  const extraExpenses = expenses.reduce((s, e) => s + Number(e.amount || 0), 0);
  const profit = revenue - opCost - extraExpenses;

  // margem por camião
  const byTruck = {};
  trips.forEach((t) => {
    const key = t.truckId || "sem";
    const c = tripCost(t);
    byTruck[key] = byTruck[key] || { revenue: 0, cost: 0, km: 0, trips: 0 };
    byTruck[key].revenue += c.price; byTruck[key].cost += c.total;
    byTruck[key].km += Number(t.distanceKm || 0); byTruck[key].trips++;
  });

  $("#main").innerHTML = `
    <div class="page-head">
      <div><h1>Financeiro</h1><p>Receitas, custos e rentabilidade</p></div>
      <button class="btn" onclick="openExpenseModal()">＋ Registar despesa</button>
    </div>
    <div class="grid kpis">
      ${kpi("Receita total", money(revenue))}
      ${kpi("Custos operacionais", money(opCost))}
      ${kpi("Outras despesas", money(extraExpenses))}
      ${kpi("Lucro líquido", money(profit), profit >= 0 ? "ok" : "danger")}
    </div>

    <div class="grid cols-2" style="margin-top:18px">
      <div class="card">
        <h3>📈 Rentabilidade por camião</h3>
        ${Object.keys(byTruck).length ? `<div class="table-wrap"><table>
          <thead><tr><th>Camião</th><th>Viagens</th><th>Km</th><th>Receita</th><th>Custo</th><th>Margem</th></tr></thead>
          <tbody>${Object.entries(byTruck).map(([k, v]) => {
            const truck = k === "sem" ? null : Store.get("trucks", k);
            const m = v.revenue - v.cost;
            return `<tr>
              <td>${truck ? esc(truck.plate) : "<span class='hint'>sem camião</span>"}</td>
              <td>${v.trips}</td><td>${num(v.km,1)}</td>
              <td>${money(v.revenue)}</td><td>${money(v.cost)}</td>
              <td class="${m>=0?'pos':'neg'}">${money(m)}</td>
            </tr>`;
          }).join("")}</tbody></table></div>` : `<div class="empty">Sem dados.</div>`}
      </div>
      <div class="card">
        <h3>🧾 Despesas registadas</h3>
        ${expenses.length ? `<div class="table-wrap"><table>
          <thead><tr><th>Data</th><th>Tipo</th><th>Camião</th><th>Valor</th><th></th></tr></thead>
          <tbody>${expenses.slice().reverse().map((e) => {
            const truck = e.truckId ? Store.get("trucks", e.truckId) : null;
            return `<tr>
              <td>${fmtDate(e.date)}</td><td>${esc(e.type)}</td>
              <td>${truck ? esc(truck.plate) : "—"}</td><td>${money(e.amount)}</td>
              <td><button class="icon-btn" onclick="delEntity('expenses','${e.id}','finance')">🗑️</button></td>
            </tr>`;
          }).join("")}</tbody></table></div>` : `<div class="empty">Sem despesas registadas.</div>`}
      </div>
    </div>
  `;
};

window.openExpenseModal = function () {
  const trucks = Store.list("trucks");
  const types = ["Combustível", "Manutenção", "Portagens", "Seguro", "Salários", "Outros"];
  openModal("Registar despesa", `
    <div class="form-row">
      <label class="field">Tipo<select id="e-type">${types.map(t=>`<option>${t}</option>`).join("")}</select></label>
      <label class="field">Valor (€) <span class="req">*</span><input id="e-amount" type="number" step="0.01" min="0" /></label>
    </div>
    <div class="form-row">
      <label class="field">Data<input id="e-date" type="date" value="${new Date().toISOString().slice(0,10)}" /></label>
      <label class="field">Camião (opcional)<select id="e-truck"><option value="">—</option>${trucks.map(t=>`<option value="${t.id}">${esc(t.plate)}</option>`).join("")}</select></label>
    </div>
    <label class="field">Notas<textarea id="e-notes" rows="2"></textarea></label>
  `, [
    { label: "Cancelar", class: "ghost", onClick: closeModal },
    { label: "Guardar", onClick: () => {
      const amount = Number($("#e-amount").value || 0);
      if (!amount) return toast("Indica o valor.", true);
      Store.upsert("expenses", {
        type: $("#e-type").value, amount, date: $("#e-date").value,
        truckId: $("#e-truck").value || null, notes: $("#e-notes").value.trim(),
      });
      closeModal(); navigate("finance"); toast("Despesa registada.");
    } },
  ]);
};

/* ==================================================================
 * VISTA: Definições
 * ================================================================== */
views.settings = function () {
  const s = Store.getSettings();
  $("#main").innerHTML = `
    <div class="page-head"><div><h1>Definições</h1><p>Parâmetros de cálculo e integração de mapas</p></div></div>
    <div class="grid cols-2">
      <div class="card">
        <h3>🔑 Routing (OpenRouteService)</h3>
        <label class="field">Chave da API ORS
          <input id="s-key" value="${esc(s.orsApiKey||"")}" placeholder="cole aqui a chave grátis" />
          <span class="hint">Grátis em openrouteservice.org/sign-up. Ativa o cálculo real de rotas para pesados (HGV). Sem chave, usa-se uma estimativa.</span>
        </label>
        <div class="form-row-3">
          <label class="field">Preço gasóleo (€/L)<input id="s-fuel" type="number" step="0.01" value="${s.fuelPricePerL}" /></label>
          <label class="field">Custo motorista (€/h)<input id="s-driver" type="number" step="0.5" value="${s.driverCostPerHour}" /></label>
          <label class="field">Máx. condução/dia (h)<input id="s-hours" type="number" step="0.5" value="${s.maxDailyDrivingHours}" /></label>
        </div>
        <button class="btn" onclick="saveSettingsForm()">Guardar definições</button>
      </div>
      <div class="card">
        <h3>💾 Dados</h3>
        <p class="hint">Os dados são guardados apenas neste navegador (localStorage). Faz backup regularmente.</p>
        <div style="display:flex;gap:10px;flex-wrap:wrap;margin-top:10px">
          <button class="btn ghost" onclick="exportData()">⬇️ Exportar backup</button>
          <button class="btn ghost" onclick="$('#import-file').click()">⬆️ Importar backup</button>
          <button class="btn ghost" onclick="loadDemo()">✨ Carregar dados de exemplo</button>
          <button class="btn danger" onclick="resetData()">🗑️ Apagar tudo</button>
        </div>
        <input type="file" id="import-file" class="hidden" accept="application/json" onchange="importData(this)" />
      </div>
    </div>
  `;
};

window.saveSettingsForm = function () {
  Store.saveSettings({
    orsApiKey: $("#s-key").value.trim(),
    fuelPricePerL: Number($("#s-fuel").value || 0),
    driverCostPerHour: Number($("#s-driver").value || 0),
    maxDailyDrivingHours: Number($("#s-hours").value || 9),
  });
  toast("Definições guardadas.");
};
window.exportData = function () {
  const blob = new Blob([Store.exportJSON()], { type: "application/json" });
  const a = document.createElement("a");
  a.href = URL.createObjectURL(blob);
  a.download = "transfrota-backup.json";
  a.click();
};
window.importData = function (input) {
  const file = input.files[0];
  if (!file) return;
  const reader = new FileReader();
  reader.onload = () => {
    try { Store.importJSON(reader.result); toast("Backup importado."); navigate("dashboard"); }
    catch (e) { toast("Ficheiro inválido.", true); }
  };
  reader.readAsText(file);
};
window.loadDemo = function () {
  if (Store.seedDemo()) { toast("Dados de exemplo carregados."); navigate("dashboard"); }
  else toast("Já existem dados — apaga tudo primeiro para carregar o exemplo.", true);
};
window.resetData = function () {
  if (confirm("Apagar TODOS os dados? Esta ação é irreversível.")) { Store.reset(); toast("Dados apagados."); navigate("dashboard"); }
};

window.delEntity = function (collection, id, view) {
  if (confirm("Eliminar este registo?")) { Store.remove(collection, id); navigate(view); toast("Eliminado."); }
};

/* ------------------------- Arranque ------------------------- */
navigate("dashboard");
