import { getCookieCache } from "better-auth/cookies"
import { NextRequest, NextResponse } from "next/server"

import { isAllowedHost } from "@/config/allowed-hosts"

// Rotas públicas explícitas (não autenticadas)
// Permite handshake de máquina sem sessão prévia para criar a sessão de máquina.
const PUBLIC_PATHS = [/^\/login$/, /^\/machines\/handshake$/]
// Rotas somente admin
const ADMIN_ONLY_PATHS = [/^\/admin(?:$|\/)/]
const APP_HOME = "/dashboard"

export async function proxy(request: NextRequest) {
  if (process.env.NODE_ENV === "production" && !isAllowedHost(request.headers.get("host"))) {
    return new NextResponse("Invalid Host header", { status: 403 })
  }

  const { pathname, searchParams, search } = request.nextUrl

  if (pathname.startsWith("/api")) {
    return NextResponse.next()
  }

  if (PUBLIC_PATHS.some((pattern) => pattern.test(pathname))) return NextResponse.next()

  const session = await getCookieCache(request)

  if (!session?.user) {
    const hasSessionCookie = Boolean(request.cookies.get("better-auth.session-token"))
    const hasRefreshCookie =
      Boolean(request.cookies.get("better-auth.refresh-token")) ||
      Boolean(request.cookies.get("better-auth.refresh-token-v2"))

    if (hasSessionCookie || hasRefreshCookie) {
      const refreshed = await attemptSessionRefresh(request)
      if (refreshed) {
        return refreshed
      }
    }

    const redirectUrl = new URL("/login", request.url)
    redirectUrl.searchParams.set("callbackUrl", pathname + search)
    return NextResponse.redirect(redirectUrl)
  }

  const role = (session.user as { role?: string })?.role?.toLowerCase() ?? "agent"
  const machinePersona =
    role === "machine"
      ? ((session.user as unknown as { machinePersona?: string }).machinePersona ?? "").toLowerCase()
      : null

  if (pathname === "/login") {
    const callback = searchParams.get("callbackUrl") ?? undefined
    const defaultDestination =
      role === "machine"
        ? machinePersona === "manager"
          ? "/dashboard"
          : "/portal/tickets"
        : APP_HOME
    const target = callback && !callback.startsWith("/login") ? callback : defaultDestination
    return NextResponse.redirect(new URL(target, request.url))
  }

  // Ajusta destinos conforme persona da máquina para evitar loops login<->dashboard
  if (role === "machine") {
    // Evita enviar colaborador ao dashboard; redireciona para o Portal
    if (pathname.startsWith("/dashboard") && machinePersona !== "manager") {
      return NextResponse.redirect(new URL("/portal/tickets", request.url))
    }
    // Evita mostrar login quando já há sessão de máquina
  }

  const isAdmin = role === "admin"
  // Em desenvolvimento, evitamos bloquear rotas admin por possíveis diferenças
  // de cache de cookie/sessão entre dev server e middleware. Em produção, aplica o gate.
  if (
    process.env.NODE_ENV === "production" &&
    !isAdmin &&
    ADMIN_ONLY_PATHS.some((pattern) => pattern.test(pathname))
  ) {
    return NextResponse.redirect(new URL(APP_HOME, request.url))
  }

  return NextResponse.next()
}

export const config = {
  runtime: "nodejs",
  // Evita executar para assets e imagens estáticas
  matcher: ["/((?!_next/static|_next/image|favicon.ico|icon.png).*)"],
}

async function attemptSessionRefresh(request: NextRequest): Promise<NextResponse | null> {
  try {
    const refreshUrl = new URL("/api/auth/get-session", request.url)
    const response = await fetch(refreshUrl, {
      method: "GET",
      headers: {
        cookie: request.headers.get("cookie") ?? "",
      },
    })

    if (!response.ok) {
      return null
    }

    const data = await response.json().catch(() => null)
    if (!data?.user) {
      return null
    }

    const redirect = NextResponse.redirect(request.nextUrl)
    const headersWithGetSetCookie = response.headers as Headers & { getSetCookie?: () => string[] | undefined }
    let setCookieHeaders =
      typeof headersWithGetSetCookie.getSetCookie === "function"
        ? headersWithGetSetCookie.getSetCookie() ?? []
        : []

    if (setCookieHeaders.length === 0) {
      const single = response.headers.get("set-cookie")
      if (single) {
        setCookieHeaders = [single]
      }
    }

    for (const cookie of setCookieHeaders) {
      redirect.headers.append("set-cookie", cookie)
    }

    return redirect
  } catch {
    return null
  }
}
