// mb-api.jsx — camada de comunicação com a API Morar Bem
// Carregado antes de qualquer outro arquivo JSX.

// Altura da tab bar incluindo a safe-area do iPhone real.
// Usar como string em inline-styles: paddingBottom: TAB_H
const TAB_H  = "calc(72px + env(safe-area-inset-bottom, 0px))";
const TAB_H2 = "calc(80px + env(safe-area-inset-bottom, 0px))"; // um pouco mais folgado

// Padding-top considerando status bar / notch do dispositivo real
const TOP_H  = "max(52px, calc(20px + env(safe-area-inset-top, 0px)))";
const TOP_H2 = "max(58px, calc(20px + env(safe-area-inset-top, 0px)))";

const API_BASE = (window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1")
  ? "http://localhost:8080"
  : window.location.origin;

// ── Token storage ─────────────────────────────────────────────
const Auth = {
  get: ()      => localStorage.getItem("mb_token"),
  set: (t)     => localStorage.setItem("mb_token", t),
  setRefresh: (t) => localStorage.setItem("mb_refresh", t),
  getRefresh: ()  => localStorage.getItem("mb_refresh"),
  clear: ()    => { localStorage.removeItem("mb_token"); localStorage.removeItem("mb_refresh"); },
  isLogged: () => !!localStorage.getItem("mb_token"),
};

// ── Fetch base ────────────────────────────────────────────────
async function apiFetch(path, { method = "GET", body, auth = true, idempotencyKey } = {}) {
  const headers = { "Content-Type": "application/json" };
  if (auth) {
    const token = Auth.get();
    if (token) headers["Authorization"] = "Bearer " + token;
  }
  if (idempotencyKey) headers["Idempotency-Key"] = idempotencyKey;

  const res = await fetch(API_BASE + path, {
    method,
    headers,
    body: body != null ? JSON.stringify(body) : undefined,
  });

  // Auto-refresh se 401
  if (res.status === 401 && auth) {
    const refresh = Auth.getRefresh();
    if (refresh) {
      const r = await fetch(API_BASE + "/auth/refresh", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ refresh_token: refresh }),
      });
      if (r.ok) {
        const { access_token, refresh_token } = await r.json();
        Auth.set(access_token);
        Auth.setRefresh(refresh_token);
        headers["Authorization"] = "Bearer " + access_token;
        const retry = await fetch(API_BASE + path, { method, headers, body: body ? JSON.stringify(body) : undefined });
        return retry.ok ? retry.json() : Promise.reject(await retry.json());
      }
    }
    Auth.clear();
    return Promise.reject({ status: 401, title: "Sessão expirada" });
  }

  if (!res.ok) return Promise.reject(await res.json().catch(() => ({ status: res.status })));
  if (res.status === 204) return null;
  return res.json();
}

// ── API endpoints ─────────────────────────────────────────────
const API = {

  // Auth
  auth: {
    register:  (b) => apiFetch("/auth/customer/register", { method: "POST", body: b, auth: false }),
    login:     (b) => apiFetch("/auth/customer/login",    { method: "POST", body: b, auth: false }),
    forgot:    (b) => apiFetch("/auth/customer/forgot",   { method: "POST", body: b, auth: false }),
    verifyOtp: (b) => apiFetch("/auth/customer/verify-otp", { method: "POST", body: b, auth: false }),
    reset:     (b) => apiFetch("/auth/customer/reset",    { method: "POST", body: b, auth: false }),
    refresh:   ()  => apiFetch("/auth/refresh", { method: "POST", body: { refresh_token: Auth.getRefresh() }, auth: false }),
  },

  // Perfil
  me: {
    get:    ()  => apiFetch("/me"),
    update: (b) => apiFetch("/me", { method: "PATCH", body: b }),
    addresses:       () => apiFetch("/me/addresses"),
    addAddress:    (b) => apiFetch("/me/addresses", { method: "POST", body: b }),
    deleteAddress: (id) => apiFetch(`/me/addresses/${id}`, { method: "DELETE" }),
    paymentMethods:  () => apiFetch("/me/payment-methods"),
    favorites:       () => apiFetch("/me/favorites"),
    addFavorite:   (id) => apiFetch(`/me/favorites/${id}`, { method: "POST" }),
    removeFavorite:(id) => apiFetch(`/me/favorites/${id}`, { method: "DELETE" }),
    validateCoupon:(c)  => apiFetch(`/me/coupons/validate?code=${encodeURIComponent(c)}`),
    notifications:   () => apiFetch("/me/notifications"),
    markNotifsRead:  () => apiFetch("/me/notifications/read", { method: "POST" }),
  },

  // Carteira
  wallet: {
    get:          () => apiFetch("/wallet"),
    transactions: () => apiFetch("/wallet/transactions"),
  },

  // Conteúdo público
  home:               () => apiFetch("/home", { auth: false }),
  regions:            () => apiFetch("/regions", { auth: false }),
  segments:           () => apiFetch("/segments", { auth: false }),
  guideEditions:      () => apiFetch("/guide-editions", { auth: false }),
  journeyStages:      () => apiFetch("/journey-stages", { auth: false }),
  homeServiceCats:    () => apiFetch("/home-service-categories", { auth: false }),
  gastroCuisines:  () => apiFetch("/gastro-categories", { auth: false }),
  gastroPartners: (id, params = {}) => {
    const q = new URLSearchParams();
    if (params.regionId) q.set("region_id", params.regionId);
    return apiFetch(`/gastro-categories/${encodeURIComponent(id)}/companies?${q}`, { auth: false });
  },
  designAssets:       () => apiFetch("/design-assets", { auth: false }),

  // Descobrir
  discover: (params = {}) => {
    const q = new URLSearchParams();
    if (params.regionId)   q.set("region_id",   params.regionId);
    if (params.segmentId)  q.set("segment_id",  params.segmentId);
    if (params.categoryId) q.set("category_id", params.categoryId);
    if (params.lat != null) q.set("lat", params.lat);
    if (params.lng != null) q.set("lng", params.lng);
    if (params.radius)     q.set("radius",      params.radius);
    if (params.mode)       q.set("mode",        params.mode);
    if (params.page)       q.set("page",        params.page);
    return apiFetch("/discover/companies?" + q.toString(), { auth: false });
  },

  // Parceiro / catálogo
  company:   (id) => apiFetch(`/companies/${id}`, { auth: false }),
  products:  (id) => apiFetch(`/companies/${id}/products`, { auth: false }),
  services:  (id) => apiFetch(`/companies/${id}/services`, { auth: false }),
  listings:  (id) => apiFetch(`/companies/${id}/listings`, { auth: false }),
  companyReviews:  (id) => apiFetch(`/companies/${id}/reviews`),
  myCompanyReview: (id) => apiFetch(`/companies/${id}/my-review`),
  createCompanyReview: (id, b) => apiFetch(`/companies/${id}/reviews`, { method: "POST", body: b }),

  // Pedidos
  orders: {
    create: (b, key) => apiFetch("/orders", { method: "POST", body: { ...b, idempotency_key: key || crypto.randomUUID() } }),
    list:   ()       => apiFetch("/orders"),
    get:    (id)     => apiFetch(`/orders/${id}`),
    review: (id, b)  => apiFetch(`/orders/${id}/review`, { method: "POST", body: b }),
  },

  // Agendamentos
  appointments: {
    create:    (b)   => apiFetch("/appointments", { method: "POST", body: b }),
    list:      ()    => apiFetch("/appointments"),
    get:       (id)  => apiFetch(`/appointments/${id}`),
    cancel:    (id)  => apiFetch(`/appointments/${id}/cancel`, { method: "PATCH" }),
    reschedule:(id,b)=> apiFetch(`/appointments/${id}/reschedule`, { method: "PATCH", body: b }),
  },

  // Leads
  leads: {
    create: (b) => apiFetch("/leads", { method: "POST", body: b }),
    list:   ()  => apiFetch("/leads"),
  },

  // Clube
  club: {
    plans:      () => apiFetch("/club/plans", { auth: false }),
    subscribe: (b)  => apiFetch("/club/subscribe", { method: "POST", body: b }),
    subscription: () => apiFetch("/club/subscription"),
    cancel:     ()  => apiFetch("/club/cancel", { method: "POST" }),
  },

  // Blog
  blog: {
    categories: () => apiFetch("/blog/categories", { auth: false }),
    posts: (params = {}) => {
      const q = new URLSearchParams();
      if (params.category_id) q.set("category_id", params.category_id);
      if (params.page) q.set("page", params.page);
      return apiFetch("/blog/posts?" + q, { auth: false });
    },
    post: (id) => apiFetch(`/blog/posts/${id}`, { auth: false }),
  },
};

// ── Helpers ───────────────────────────────────────────────────

// Cálculo de distância Haversine (km) entre dois pontos
function haversineKm(lat1, lng1, lat2, lng2) {
  if (!lat1 || !lng1 || !lat2 || !lng2) return null;
  const R = 6371, toRad = x => x * Math.PI / 180;
  const dLat = toRad(lat2 - lat1), dLng = toRad(lng2 - lng1);
  const a = Math.sin(dLat/2)**2 + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLng/2)**2;
  return +(R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))).toFixed(1);
}

// Recalcula distâncias de uma lista de parceiros dado a posição do usuário
function recalcDistances(partners, userLat, userLng) {
  if (!userLat || !userLng) return partners;
  return partners.map(p => {
    const lat = p._raw?.latitude, lng = p._raw?.longitude;
    const dist = haversineKm(userLat, userLng, lat, lng);
    return dist != null ? { ...p, dist } : p;
  });
}

// Ordena por plano: Diamante > Ouro > Prata > Bronze > Grátis (aplicar em todo listing)
const PLAN_RANK_MAP = { Diamante: 5, Ouro: 4, Prata: 3, Bronze: 2, "Grátis": 1 };
function planRank(p) {
  return PLAN_RANK_MAP[p._raw?.plan_name || p.plan_name] || 0;
}

// Converte resposta da API para o formato do mock (retrocompatibilidade)
function apiCompanyToPartner(c) {
  return {
    id:       c.id,
    name:     c.name,
    seg:      c.segment_id || null,     // UUID — usado para filtro no ShopScreen
    cat:      null,                      // nome de categoria não vem no discover (só display)
    categoryIds: c.category_ids || [],  // UUIDs das categorias via company_categories
    region:   c.region_name || "",
    area:     (() => {
      const addr = (c.endereco || "").trim();
      if (!addr) return c.region_name || "";
      // Format "Rua X, 123 — Bairro, Cidade/SE" → "Bairro, Cidade/SE"
      if (addr.includes("—")) return addr.split("—").pop().trim() || c.region_name || "";
      // Short format "Bairro, Cidade/SE" → use as-is
      if (/\/[A-Z]{2}$/.test(addr)) return addr;
      // Full CNPJ-style address "RUA, NUM, BAIRRO, CIDADE, SE" → use region as fallback
      return c.region_name || "";
    })(),
    rating:   parseFloat(c.rating) || 0,
    reviews:  c.total_avaliacoes || 0,
    cashback: parseFloat(c.bemcash_padrao_pct) || 0,
    turbo:    parseFloat(c.bemcash_turbo_pct) || 0,
    dist:     c.dist_km != null ? +parseFloat(c.dist_km).toFixed(1) : 0,
    fee:      parseFloat(c.taxa_entrega) || 0,
    free:     parseFloat(c.frete_gratis_acima) || 0,
    time:     c.tempo_estimado || "",
    delivery: c.aceita_entrega,
    pickup:   c.aceita_retirada,
    open:     c.status === "active",
    tags:     c.bemcash_turbo_pct > 0 ? ["Turbo"] : [],
    color:    c.color || "#1E63C8",
    blurb:    c.sobre || "",
    instagram:c.instagram,
    video:    c.video_url,
    phone:    c.telefone,
    whatsapp: c.whatsapp,
    horario:  c.horario,
    address:  c.endereco,
    type:     c.type === "divulga" ? "vitrine" : c.type,
    hub:      c.hub_only,
    lojaOn:   c.loja_habilitada,
    cashbackOn: c.bemcash_habilitado,
    logoUrl:  c.logo_url || null,
    coverUrl: c.cover_url || null,
    photoUrls: c.photo_urls || [],
    plan_name: c.plan_name || null,
    _raw:     c, // objeto original completo
  };
}

function apiWalletToMock(w, txs = []) {
  return {
    balance: parseFloat(w.balance_available) || 0,
    pending: parseFloat(w.balance_pending) || 0,
    movements: (txs || []).map(t => ({
      id:     t.id,
      kind:   t.kind,
      turbo:  t.is_turbo,
      label:  t.label,
      date:   new Date(t.created_at).toLocaleDateString("pt-BR", { day: "2-digit", month: "short" }),
      value:  t.kind === "out" ? -parseFloat(t.amount) : parseFloat(t.amount),
    })),
  };
}

function apiOrderToMock(o) {
  return {
    id:            o.id,
    partner:       o.company_id,
    status:        statusLabel(o.status),
    rawStatus:     o.status,
    date:          new Date(o.created_at).toLocaleDateString("pt-BR", { day: "2-digit", month: "short" }),
    total:         parseFloat(o.total) || 0,
    cashback:      parseFloat(o.bemcash_creditado) || 0,
    turbo:         parseFloat(o.bemcash_turbo_creditado) || 0,
    items:         (o.items || []).map(i => i.name),
    mode:          o.mode === "entrega" ? "Entrega" : "Retirada",
    rated:         false,
    checkoutUrl:   o.mp_checkout_url || null,
    _raw:          o,
  };
}

function apiApptToMock(a) {
  return {
    id:       a.id,
    partner:  a.company_id,
    service:  a.service_name,
    date:     a.scheduled_date?.slice(0, 10).split("-").reverse().join(" ").replace(" ", " ").replace("-", " ") || "",
    time:     a.scheduled_time?.slice(0, 5) || "",
    local:    a.local,
    status:   apptStatusLabel(a.status),
    upcoming: a.status === "solicitado" || a.status === "confirmado",
    rated:    false,
    _raw:     a,
  };
}

function statusLabel(s) {
  return {
    aguardando_pagamento: "Aguardando pagamento",
    pendente: "Aguardando", em_preparo: "Em preparo", saiu_para_entrega: "A caminho",
    entregue: "Entregue", concluido: "Avaliar", recusado: "Recusado", cancelado: "Cancelado",
  }[s] || s;
}
function apptStatusLabel(s) {
  return { solicitado: "Aguardando", confirmado: "Confirmado", em_atendimento: "Em andamento",
    concluido: "Concluído", cancelado: "Cancelado" }[s] || s;
}

// Expõe globalmente
Object.assign(window, { API, Auth, apiFetch, apiCompanyToPartner, haversineKm, recalcDistances, planRank, apiWalletToMock, apiOrderToMock, apiApptToMock, TAB_H, TAB_H2, TOP_H, TOP_H2 });
