import { randomBytes } from "crypto"
import type { Prisma } from "@/lib/prisma"
import { DEFAULT_TENANT_ID } from "@/lib/constants"
import { env } from "@/lib/env"
import { normalizeSlug, slugify } from "@/lib/slug"
import { prisma } from "@/lib/prisma"
import { createCorsPreflight, jsonWithCors } from "@/server/cors"
import { ConvexConfigurationError } from "@/server/convex-client"
import { syncConvexCompany } from "@/server/companies-sync"
import { safeCompanyFindMany } from "@/server/company-service"

export const runtime = "nodejs"

const CORS_METHODS = "GET, POST, OPTIONS"

function extractSecret(request: Request, url: URL): string | null {
  const header =
    request.headers.get("x-machine-secret") ??
    request.headers.get("x-machine-provisioning-secret") ??
    request.headers.get("x-provisioning-secret")
  if (header && header.trim()) return header.trim()

  const auth = request.headers.get("authorization")
  if (auth && auth.toLowerCase().startsWith("bearer ")) {
    const token = auth.slice(7).trim()
    if (token) return token
  }

  const querySecret = url.searchParams.get("provisioningSecret")
  if (querySecret && querySecret.trim()) return querySecret.trim()

  return null
}

export async function OPTIONS(request: Request) {
  return createCorsPreflight(request.headers.get("origin"), CORS_METHODS)
}

export async function GET(request: Request) {
  const url = new URL(request.url)
  const origin = request.headers.get("origin")
  const secret = extractSecret(request, url)
  const expectedSecret = env.MACHINE_PROVISIONING_SECRET
  if (!expectedSecret) {
    return jsonWithCors({ error: "Provisionamento não configurado" }, 500, origin, CORS_METHODS)
  }
  if (!secret || secret !== expectedSecret) {
    return jsonWithCors({ error: "Não autorizado" }, 401, origin, CORS_METHODS)
  }

  const tenantIdRaw = url.searchParams.get("tenantId") ?? ""
  const tenantId = tenantIdRaw.trim() || DEFAULT_TENANT_ID
  const search = url.searchParams.get("search")?.trim() ?? ""

  try {
    const slugSearch = search ? normalizeSlug(search) ?? slugify(search) : null
    const orFilters: Prisma.CompanyWhereInput[] = []
    if (search) {
      orFilters.push({
        name: {
          contains: search,
          mode: "insensitive",
        } as unknown as Prisma.StringFilter<"Company">,
      })
      if (slugSearch) {
        orFilters.push({
          slug: {
            contains: slugSearch,
            mode: "insensitive",
          } as unknown as Prisma.StringFilter<"Company">,
        })
      }
    }
    const where: Prisma.CompanyWhereInput = {
      tenantId,
      ...(orFilters.length > 0 ? { OR: orFilters } : {}),
    }

    const companies = await safeCompanyFindMany({
      where,
      orderBy: { name: "asc" },
      take: 20,
    })

    return jsonWithCors(
      {
        companies: companies.map((company) => ({
          id: company.id,
          tenantId: company.tenantId,
          name: company.name,
          slug: company.slug,
        })),
      },
      200,
      origin,
      CORS_METHODS
    )
  } catch (error) {
    console.error("[machines.companies] Falha ao listar empresas", error)
    return jsonWithCors({ error: "Falha ao buscar empresas" }, 500, origin, CORS_METHODS)
  }
}

export async function POST(request: Request) {
  const url = new URL(request.url)
  const origin = request.headers.get("origin")
  const secret = extractSecret(request, url)
  const expectedSecret = env.MACHINE_PROVISIONING_SECRET
  if (!expectedSecret) {
    return jsonWithCors({ error: "Provisionamento não configurado" }, 500, origin, CORS_METHODS)
  }
  if (!secret || secret !== expectedSecret) {
    return jsonWithCors({ error: "Não autorizado" }, 401, origin, CORS_METHODS)
  }

  let payload: Partial<{ tenantId?: string; name?: string; slug?: string }>
  try {
    payload = (await request.json()) as Partial<{ tenantId?: string; name?: string; slug?: string }>
  } catch (error) {
    return jsonWithCors(
      { error: "Payload inválido", details: error instanceof Error ? error.message : String(error) },
      400,
      origin,
      CORS_METHODS
    )
  }

  const tenantId = payload?.tenantId?.trim() || DEFAULT_TENANT_ID
  const name = payload?.name?.trim() ?? ""
  const normalizedSlug = normalizeSlug(payload?.slug ?? name)
  if (!name) {
    return jsonWithCors({ error: "Informe o nome da empresa" }, 400, origin, CORS_METHODS)
  }
  if (!normalizedSlug) {
    return jsonWithCors({ error: "Não foi possível gerar um slug para a empresa" }, 400, origin, CORS_METHODS)
  }

  try {
    const existing = await prisma.company.findFirst({
      where: { tenantId, slug: normalizedSlug },
    })

    const provisioningCode = existing?.provisioningCode ?? randomBytes(32).toString("hex")

    const company =
      existing ??
      (await prisma.company.create({
        data: {
          tenantId,
          name,
          slug: normalizedSlug,
          provisioningCode,
        },
      }))

    try {
      const synced = await syncConvexCompany({
        tenantId,
        slug: company.slug,
        name: company.name,
        provisioningCode: company.provisioningCode,
      })
      if (!synced) {
        throw new ConvexConfigurationError()
      }
    } catch (error) {
      if (error instanceof ConvexConfigurationError) {
        return jsonWithCors({ error: error.message }, 500, origin, CORS_METHODS)
      }
      throw error
    }

    return jsonWithCors(
      {
        company: {
          id: company.id,
          tenantId: company.tenantId,
          name: company.name,
          slug: company.slug,
          created: existing ? false : true,
        },
      },
      existing ? 200 : 201,
      origin,
      CORS_METHODS
    )
  } catch (error) {
    const prismaError = error as { code?: string }
    if (prismaError?.code === "P2002") {
      try {
        const fallback = await prisma.company.findFirst({ where: { tenantId, slug: normalizedSlug } })
        if (fallback) {
          try {
            await syncConvexCompany({
              tenantId,
              slug: fallback.slug,
              name: fallback.name,
              provisioningCode: fallback.provisioningCode,
            })
          } catch (error) {
            if (error instanceof ConvexConfigurationError) {
              return jsonWithCors({ error: error.message }, 500, origin, CORS_METHODS)
            }
            throw error
          }
          return jsonWithCors(
            {
              company: {
                id: fallback.id,
                tenantId: fallback.tenantId,
                name: fallback.name,
                slug: fallback.slug,
                created: false,
              },
            },
            200,
            origin,
            CORS_METHODS
          )
        }
      } catch (lookupError) {
        console.error("[machines.companies] Falha ao recuperar empresa após conflito", lookupError)
      }
    }
    console.error("[machines.companies] Falha ao criar empresa", error)
    return jsonWithCors({ error: "Falha ao criar ou recuperar empresa" }, 500, origin, CORS_METHODS)
  }
}
