import { NextResponse } from "next/server";
import { createClient } from "@/lib/supabase-server";

/**
 * CEP para endereco e coordenada.
 *
 * Passa pelo servidor, e nao direto do navegador, por tres motivos: nao expor
 * de quais servicos dependemos, poder trocar de fonte sem mexer na tela, e
 * guardar em cache — CEP nao muda, e a mesma rua e consultada varias vezes ao
 * marcar visitas no mesmo bairro.
 *
 * A BrasilAPI devolve latitude e longitude junto do endereco, o que dispensa
 * um servico separado de geocodificacao. Quando ela nao tem a coordenada, o
 * ViaCEP ainda salva o endereco — melhor um pino a menos que um formulario
 * que a pessoa precisa preencher a mao.
 */

export const dynamic = "force-dynamic";

type Resultado = {
  cep: string;
  rua: string;
  bairro: string;
  cidade: string;
  uf: string;
  lat: number | null;
  lng: number | null;
  fonte: string;
};

/* CEP nao muda: uma hora de cache poupa ida a rede em quem marca varias
   visitas na mesma regiao. */
const CACHE_MS = 60 * 60 * 1000;
const cache = new Map<string, { dados: Resultado; expira: number }>();

function numero(v: unknown): number | null {
  const n = Number(v);
  return Number.isFinite(n) && n !== 0 ? n : null;
}

async function pelaBrasilApi(cep: string): Promise<Resultado | null> {
  const r = await fetch(`https://brasilapi.com.br/api/cep/v2/${cep}`, {
    signal: AbortSignal.timeout(6000),
  });
  if (!r.ok) return null;
  const j = (await r.json()) as {
    street?: string; neighborhood?: string; city?: string; state?: string;
    location?: { coordinates?: { latitude?: string; longitude?: string } };
  };
  return {
    cep,
    rua: j.street || "",
    bairro: j.neighborhood || "",
    cidade: j.city || "",
    uf: j.state || "",
    lat: numero(j.location?.coordinates?.latitude),
    lng: numero(j.location?.coordinates?.longitude),
    fonte: "brasilapi",
  };
}

async function peloViaCep(cep: string): Promise<Resultado | null> {
  const r = await fetch(`https://viacep.com.br/ws/${cep}/json/`, {
    signal: AbortSignal.timeout(6000),
  });
  if (!r.ok) return null;
  const j = (await r.json()) as {
    erro?: boolean | string; logradouro?: string; bairro?: string;
    localidade?: string; uf?: string;
  };
  if (j.erro) return null;
  return {
    cep,
    rua: j.logradouro || "",
    bairro: j.bairro || "",
    cidade: j.localidade || "",
    uf: j.uf || "",
    lat: null,
    lng: null,
    fonte: "viacep",
  };
}

export async function GET(req: Request) {
  const supabase = await createClient();
  const {
    data: { user },
  } = await supabase.auth.getUser();
  /* Exige sessao para a rota nao virar um consultor de CEP publico as custas
     do servidor de outra pessoa. */
  if (!user) return NextResponse.json({ error: "Nao autenticado." }, { status: 401 });

  const cep = String(new URL(req.url).searchParams.get("cep") || "").replace(/\D/g, "");
  if (cep.length !== 8) {
    return NextResponse.json({ error: "CEP precisa de 8 dígitos." }, { status: 400 });
  }

  const guardado = cache.get(cep);
  if (guardado && guardado.expira > Date.now()) {
    return NextResponse.json({ ok: true, ...guardado.dados, doCache: true });
  }

  try {
    const dados = (await pelaBrasilApi(cep)) ?? (await peloViaCep(cep));
    if (!dados) {
      return NextResponse.json({ error: "CEP não encontrado." }, { status: 404 });
    }
    cache.set(cep, { dados, expira: Date.now() + CACHE_MS });
    return NextResponse.json({ ok: true, ...dados });
  } catch {
    return NextResponse.json({ error: "Não consegui consultar o CEP agora." }, { status: 503 });
  }
}
