import { NextResponse } from "next/server"
import type { Id } from "@/convex/_generated/dataModel"
import type { UserRole } from "@prisma/client"
import { api } from "@/convex/_generated/api"
import { ConvexHttpClient } from "convex/browser"
import { prisma } from "@/lib/prisma"
import { DEFAULT_TENANT_ID } from "@/lib/constants"
import { assertStaffSession } from "@/lib/auth-server"
import { ROLE_OPTIONS, type RoleOption, isAdmin } from "@/lib/authz"

function normalizeRole(input: string | null | undefined): RoleOption {
  const candidate = (input ?? "agent").toLowerCase() as RoleOption
  return ((ROLE_OPTIONS as readonly string[]).includes(candidate) ? candidate : "agent") as RoleOption
}

const USER_ROLE_OPTIONS: ReadonlyArray<UserRole> = ["ADMIN", "MANAGER", "AGENT", "COLLABORATOR"]

function mapToUserRole(role: RoleOption): UserRole {
  const candidate = role.toUpperCase() as UserRole
  return USER_ROLE_OPTIONS.includes(candidate) ? candidate : "AGENT"
}

function canManageRole(role: string | null | undefined) {
  const normalized = (role ?? "").toLowerCase()
  return normalized !== "admin" && normalized !== "agent"
}

export const runtime = "nodejs"

export async function GET(_: Request, { params }: { params: Promise<{ id: string }> }) {
  const { id } = await params
  const session = await assertStaffSession()
  if (!session) {
    return NextResponse.json({ error: "Não autorizado" }, { status: 401 })
  }

  const user = await prisma.authUser.findUnique({
    where: { id },
    select: {
      id: true,
      email: true,
      name: true,
      role: true,
      tenantId: true,
      machinePersona: true,
      createdAt: true,
      updatedAt: true,
    },
  })

  if (!user) {
    return NextResponse.json({ error: "Usuário não encontrado" }, { status: 404 })
  }

  const domain = await prisma.user.findUnique({
    where: { email: user.email },
    select: {
      companyId: true,
      company: { select: { name: true } },
    },
  })

  return NextResponse.json({
    user: {
      id: user.id,
      email: user.email,
      name: user.name ?? "",
      role: normalizeRole(user.role),
      tenantId: user.tenantId ?? DEFAULT_TENANT_ID,
      createdAt: user.createdAt.toISOString(),
      updatedAt: user.updatedAt?.toISOString() ?? null,
      companyId: domain?.companyId ?? null,
      companyName: domain?.company?.name ?? null,
      machinePersona: user.machinePersona ?? null,
    },
  })
}

export async function PATCH(request: Request, { params }: { params: Promise<{ id: string }> }) {
  const { id } = await params
  const session = await assertStaffSession()
  if (!session) {
    return NextResponse.json({ error: "Não autorizado" }, { status: 401 })
  }
  const sessionIsAdmin = isAdmin(session.user.role)

  const payload = (await request.json().catch(() => null)) as {
    name?: string
    email?: string
    role?: RoleOption
    tenantId?: string
    companyId?: string | null
  } | null

  if (!payload || typeof payload !== "object") {
    return NextResponse.json({ error: "Payload inválido" }, { status: 400 })
  }

  const user = await prisma.authUser.findUnique({ where: { id } })
  if (!user) {
    return NextResponse.json({ error: "Usuário não encontrado" }, { status: 404 })
  }

  const nextName = payload.name?.trim() ?? user.name ?? ""
  const nextEmail = (payload.email ?? user.email).trim().toLowerCase()
  const nextRole = normalizeRole(payload.role ?? user.role)
  const nextTenant = (payload.tenantId ?? user.tenantId ?? DEFAULT_TENANT_ID).trim() || DEFAULT_TENANT_ID
  const companyId = payload.companyId ? payload.companyId : null

  if (!nextEmail || !nextEmail.includes("@")) {
    return NextResponse.json({ error: "Informe um e-mail válido" }, { status: 400 })
  }

  if (!sessionIsAdmin && !canManageRole(user.role)) {
    return NextResponse.json({ error: "Você não pode editar esse usuário" }, { status: 403 })
  }

  if ((user.role ?? "").toLowerCase() === "machine") {
    return NextResponse.json({ error: "Ajustes de máquinas devem ser feitos em Admin ▸ Máquinas" }, { status: 400 })
  }

  if (!sessionIsAdmin && !canManageRole(nextRole)) {
    return NextResponse.json({ error: "Papel inválido para este perfil" }, { status: 403 })
  }

  if (nextEmail !== user.email) {
    const conflict = await prisma.authUser.findUnique({ where: { email: nextEmail } })
    if (conflict && conflict.id !== user.id) {
      return NextResponse.json({ error: "Já existe um usuário com este e-mail" }, { status: 409 })
    }
  }

  const updated = await prisma.authUser.update({
    where: { id: user.id },
    data: {
      name: nextName,
      email: nextEmail,
      role: nextRole,
      tenantId: nextTenant,
    },
  })

  if (nextEmail !== user.email) {
    const credentialAccount = await prisma.authAccount.findFirst({
      where: { userId: user.id, providerId: "credential" },
    })
    if (credentialAccount) {
      await prisma.authAccount.update({ where: { id: credentialAccount.id }, data: { accountId: nextEmail } })
    }
  }

  const previousEmail = user.email
  const domainUser = await prisma.user.findUnique({ where: { email: previousEmail } })
  const companyData = companyId
    ? await prisma.company.findUnique({ where: { id: companyId } })
    : null

  if (companyId && !companyData) {
    return NextResponse.json({ error: "Empresa não encontrada" }, { status: 400 })
  }

  if (domainUser) {
    await prisma.user.update({
      where: { id: domainUser.id },
      data: {
        email: nextEmail,
        name: nextName || domainUser.name,
        role: mapToUserRole(nextRole),
        tenantId: nextTenant,
        companyId: companyId ?? null,
      },
    })
  } else {
    await prisma.user.upsert({
      where: { email: nextEmail },
      update: {
        name: nextName || nextEmail,
        role: mapToUserRole(nextRole),
        tenantId: nextTenant,
        companyId: companyId ?? null,
      },
      create: {
        email: nextEmail,
        name: nextName || nextEmail,
        role: mapToUserRole(nextRole),
        tenantId: nextTenant,
        companyId: companyId ?? null,
      },
    })
  }

  const convexUrl = process.env.NEXT_PUBLIC_CONVEX_URL
  if (convexUrl) {
    try {
      const convex = new ConvexHttpClient(convexUrl)
      await convex.mutation(api.users.ensureUser, {
        tenantId: nextTenant,
        email: nextEmail,
        name: nextName || nextEmail,
        avatarUrl: updated.avatarUrl ?? undefined,
        role: nextRole.toUpperCase(),
        companyId: companyId ? (companyId as Id<"companies">) : undefined,
      })
    } catch (error) {
      console.warn("Falha ao sincronizar usuário no Convex", error)
    }
  }

  return NextResponse.json({
    user: {
      id: updated.id,
      email: nextEmail,
      name: nextName,
      role: nextRole,
      tenantId: nextTenant,
      createdAt: updated.createdAt.toISOString(),
      updatedAt: updated.updatedAt?.toISOString() ?? null,
      companyId,
      companyName: companyData?.name ?? null,
      machinePersona: updated.machinePersona ?? null,
    },
  })
}

export async function DELETE(_: Request, { params }: { params: Promise<{ id: string }> }) {
  const { id } = await params
  const session = await assertStaffSession()
  if (!session) {
    return NextResponse.json({ error: "Não autorizado" }, { status: 401 })
  }
  const sessionIsAdmin = isAdmin(session.user.role)

  const target = await prisma.authUser.findUnique({
    where: { id },
    select: { id: true, email: true, role: true, tenantId: true },
  })

  if (!target) {
    return NextResponse.json({ error: "Usuário não encontrado" }, { status: 404 })
  }

  if (!sessionIsAdmin && !canManageRole(target.role)) {
    return NextResponse.json({ error: "Você não pode remover esse usuário" }, { status: 403 })
  }

  if (target.role === "machine") {
    return NextResponse.json({ error: "Os agentes de máquina devem ser removidos via módulo de máquinas." }, { status: 400 })
  }

  if (target.email === session.user.email) {
    return NextResponse.json({ error: "Você não pode remover o usuário atualmente autenticado." }, { status: 400 })
  }

  const convexUrl = process.env.NEXT_PUBLIC_CONVEX_URL
  const tenantId = target.tenantId ?? session.user.tenantId ?? DEFAULT_TENANT_ID

  if (convexUrl) {
    try {
      const convex = new ConvexHttpClient(convexUrl)
      const ensured = await convex.mutation(api.users.ensureUser, {
        tenantId,
        email: session.user.email,
        name: session.user.name ?? session.user.email,
        avatarUrl: session.user.avatarUrl ?? undefined,
        role: session.user.role.toUpperCase(),
      })

      const actorId = ensured?._id
      if (!actorId) {
        throw new Error("Falha ao identificar o administrador no Convex")
      }

      const convexUser = await convex.query(api.users.findByEmail, {
        tenantId,
        email: target.email,
      })

      if (convexUser?._id) {
        await convex.mutation(api.users.deleteUser, {
          userId: convexUser._id,
          actorId,
        })
      }
    } catch (error) {
      const message = error instanceof Error ? error.message : "Falha ao remover usuário na base de dados"
      return NextResponse.json({ error: message }, { status: 400 })
    }
  }

  await prisma.authUser.delete({ where: { id: target.id } })

  return NextResponse.json({ ok: true })
}
