import { afterAll, beforeAll, describe, expect, it, vi } from "bun:test"

import { updatePersonaHandler } from "../convex/machines"
import type { Doc, Id } from "../convex/_generated/dataModel"

const FIXED_NOW = 1_706_071_200_000

function buildMachine(overrides: Partial<Doc<"machines">> = {}): Doc<"machines"> {
  const machine: Record<string, unknown> = {
    _id: "machine_1" as Id<"machines">,
    tenantId: "tenant-1",
    companyId: undefined,
    companySlug: undefined,
    authUserId: undefined,
    authEmail: undefined,
    persona: "collaborator",
    assignedUserId: "user_1" as Id<"users">,
    assignedUserEmail: "old@example.com",
    assignedUserName: "Legacy User",
    assignedUserRole: "COLLABORATOR",
    hostname: "desktop-01",
    osName: "Windows",
    osVersion: "11",
    architecture: "x86_64",
    macAddresses: ["001122334455"],
    serialNumbers: [],
    fingerprint: "fingerprint",
    metadata: {},
    lastHeartbeatAt: FIXED_NOW - 1000,
    status: "online",
    isActive: true,
    createdAt: FIXED_NOW - 10_000,
    updatedAt: FIXED_NOW - 5_000,
    registeredBy: "agent:desktop",
  }
  return { ...(machine as Doc<"machines">), ...overrides }
}

describe("convex.machines.updatePersona", () => {
  let restoreConsole: (() => void) | undefined

  beforeAll(() => {
    vi.useFakeTimers()
    vi.setSystemTime(FIXED_NOW)
    const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {})
    const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {})
    restoreConsole = () => {
      errorSpy.mockRestore()
      warnSpy.mockRestore()
    }
  })

  afterAll(() => {
    restoreConsole?.()
    vi.useRealTimers()
  })

  it("clears persona even when legacy assigned user no longer exists", async () => {
    const machine = buildMachine()
    const patch = vi.fn(async () => undefined)
    const get = vi.fn(async (id: Id<"machines"> | Id<"users">) => {
      if (id === machine._id) return machine
      return null
    })

    const ctx = { db: { get, patch } } as unknown as Parameters<typeof updatePersonaHandler>[0]

    const result = await updatePersonaHandler(ctx, { machineId: machine._id, persona: "" })

    expect(result).toEqual({ ok: true, persona: null })
    expect(patch).toHaveBeenCalledTimes(1)
    expect(patch).toHaveBeenCalledWith(
      machine._id,
      expect.objectContaining({
        persona: undefined,
        assignedUserId: undefined,
        assignedUserEmail: undefined,
        assignedUserName: undefined,
        assignedUserRole: undefined,
        updatedAt: FIXED_NOW,
      })
    )
  })

  it("still validates persona assignments when user cannot be found", async () => {
    const machine = buildMachine({ persona: undefined, assignedUserId: undefined })
    const missingUserId = "user_missing" as Id<"users">
    const patch = vi.fn(async () => undefined)
    const get = vi.fn(async (id: Id<"machines"> | Id<"users">) => {
      if (id === machine._id) return machine
      if (id === missingUserId) return null
      return null
    })

    const ctx = { db: { get, patch } } as unknown as Parameters<typeof updatePersonaHandler>[0]

    await expect(
      updatePersonaHandler(ctx, {
        machineId: machine._id,
        persona: "collaborator",
        assignedUserId: missingUserId,
      })
    ).rejects.toThrow("Usuário vinculado não encontrado")

    expect(patch).not.toHaveBeenCalled()
  })
})
