import { describe, expect, it, beforeEach, vi } from "vitest"
import { NextRequest } from "next/server"

import { MACHINE_CTX_COOKIE, serializeMachineCookie } from "@/server/machines/context"

const mockAssertSession = vi.fn()
vi.mock("@/lib/auth-server", () => ({
  assertAuthenticatedSession: mockAssertSession,
}))

const mockCreateConvexClient = vi.fn()
vi.mock("@/server/convex-client", () => {
  class ConvexConfigurationError extends Error {}
  return {
    createConvexClient: mockCreateConvexClient,
    ConvexConfigurationError,
  }
})

const mockCookieStore = {
  get: vi.fn<() => unknown, []>(),
}

vi.mock("next/headers", () => ({
  cookies: vi.fn(async () => mockCookieStore),
}))

describe("GET /api/machines/session", () => {
  beforeEach(() => {
    vi.clearAllMocks()
    mockCookieStore.get.mockReturnValue(undefined)
    mockCreateConvexClient.mockReturnValue({
      query: vi.fn(),
      mutation: vi.fn(),
    })
  })

  it("returns 403 when the current session is not a machine", async () => {
    mockAssertSession.mockResolvedValue({ user: { role: "admin" } })

    const { GET } = await import("./route")
    const response = await GET(new NextRequest("https://example.com/api/machines/session"))

    expect(response.status).toBe(403)
    const payload = await response.json()
    expect(payload).toEqual({ error: "Sessão de máquina não encontrada." })
    expect(mockCreateConvexClient).not.toHaveBeenCalled()
  })

  it("returns machine context and sets cookie when lookup succeeds", async () => {
    mockAssertSession.mockResolvedValue({
      user: { role: "machine", email: "device@example.com" },
    })
    mockCookieStore.get.mockReturnValueOnce(undefined)

    const sampleContext = {
      id: "machine-123",
      tenantId: "tenant-1",
      companyId: "company-1",
      companySlug: "acme",
      persona: "manager",
      assignedUserId: "user-789",
      assignedUserEmail: "manager@acme.com",
      assignedUserName: "Manager Doe",
      assignedUserRole: "MANAGER",
      metadata: null,
      authEmail: "device@example.com",
    }

    let call = 0
    const queryMock = vi.fn(async (_route: unknown, args: unknown) => {
      call += 1
      if (call === 1) {
        expect(args).toEqual({ authEmail: "device@example.com" })
        return { id: "machine-123" }
      }
      if (call === 2) {
        expect(args).toEqual({ machineId: "machine-123" })
        return sampleContext
      }
      return null
    })

    mockCreateConvexClient.mockReturnValue({
      query: queryMock,
      mutation: vi.fn(),
    })

    const { GET } = await import("./route")
    const response = await GET(new NextRequest("https://example.com/api/machines/session"))

    expect(response.status).toBe(200)
    const payload = await response.json()
    expect(payload.machine.id).toBe(sampleContext.id)
    expect(payload.machine.assignedUserEmail).toBe(sampleContext.assignedUserEmail)

    const cookie = response.cookies.get(MACHINE_CTX_COOKIE)
    expect(cookie?.value).toBe(serializeMachineCookie({
      machineId: sampleContext.id,
      persona: sampleContext.persona,
      assignedUserId: sampleContext.assignedUserId,
      assignedUserEmail: sampleContext.assignedUserEmail,
      assignedUserName: sampleContext.assignedUserName,
      assignedUserRole: sampleContext.assignedUserRole,
    }))
  })
})
