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

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

const MACHINE_ID = "machine_1" as Id<"machines">
const TENANT_ID = "tenant-1"

function buildMachine(overrides: Partial<Doc<"machines">> = {}): Doc<"machines"> {
  const machine: Record<string, unknown> = {
    _id: MACHINE_ID,
    tenantId: TENANT_ID,
    hostname: "desktop-01",
    macAddresses: [],
    serialNumbers: [],
    fingerprint: "fp",
    isActive: true,
    lastHeartbeatAt: Date.now(),
    createdAt: Date.now() - 10_000,
    updatedAt: Date.now() - 5_000,
    linkedUserIds: [],
    remoteAccess: null,
  }
  return { ...(machine as Doc<"machines">), ...overrides }
}

function buildTicket(overrides: Partial<Doc<"tickets">> = {}): Doc<"tickets"> {
  const base: Record<string, unknown> = {
    _id: "ticket_base" as Id<"tickets">,
    tenantId: TENANT_ID,
    reference: 42600,
    subject: "Generic ticket",
    summary: "",
    status: "PENDING",
    priority: "MEDIUM",
    channel: "EMAIL",
    queueId: undefined,
    requesterId: "user_req" as Id<"users">,
    requesterSnapshot: { name: "Alice", email: "alice@example.com", avatarUrl: undefined, teams: [] },
    assigneeId: "user_assignee" as Id<"users">,
    assigneeSnapshot: { name: "Bob", email: "bob@example.com", avatarUrl: undefined, teams: [] },
    companyId: undefined,
    companySnapshot: undefined,
    machineId: MACHINE_ID,
    machineSnapshot: undefined,
    working: false,
    dueAt: undefined,
    firstResponseAt: undefined,
    resolvedAt: undefined,
    closedAt: undefined,
    updatedAt: Date.now(),
    createdAt: Date.now() - 2000,
    tags: [],
    customFields: [],
    totalWorkedMs: 0,
    internalWorkedMs: 0,
    externalWorkedMs: 0,
    activeSessionId: undefined,
  }
  return { ...(base as Doc<"tickets">), ...overrides }
}

type PaginateHandler = (options: { cursor: string | null; numItems: number }) => Promise<{
  page: Doc<"tickets">[]
  isDone: boolean
  continueCursor: string
}>

function createCtx({
  machine = buildMachine(),
  queues = new Map<string, Doc<"queues">>(),
  paginate,
}: {
  machine?: Doc<"machines">
  queues?: Map<string, Doc<"queues">>
  paginate: PaginateHandler
}) {
  const createFilterBuilder = () => {
    const builder: Record<string, (..._args: unknown[]) => typeof builder> = {}
    builder.eq = () => builder
    builder.gte = () => builder
    builder.lte = () => builder
    builder.or = () => builder
    return builder
  }

  return {
    db: {
      get: vi.fn(async (id: Id<"machines"> | Id<"queues">) => {
        if (machine && id === machine._id) return machine
        const queue = queues.get(String(id))
        if (queue) return queue
        return null
      }),
      query: vi.fn(() => {
        const chain = {
          filter: vi.fn((cb?: (builder: ReturnType<typeof createFilterBuilder>) => unknown) => {
            cb?.(createFilterBuilder())
            return chain
          }),
          paginate: vi.fn((options: { cursor: string | null; numItems: number }) => paginate(options)),
        }

        return {
          withIndex: vi.fn((_indexName: string, cb?: (builder: ReturnType<typeof createFilterBuilder>) => unknown) => {
            cb?.(createFilterBuilder())
            return {
              order: vi.fn(() => chain),
            }
          }),
        }
      }),
    },
  } as unknown as Parameters<typeof listTicketsHistoryHandler>[0]
}

describe("convex.machines.listTicketsHistory", () => {
  it("maps tickets metadata and resolves queue names", async () => {
    const machine = buildMachine()
    const ticket = buildTicket({
      _id: "ticket_1" as Id<"tickets">,
      subject: "Printer offline",
      priority: "HIGH",
      status: "PENDING",
      queueId: "queue_1" as Id<"queues">,
      updatedAt: 170000,
      createdAt: 160000,
    })

    const paginate = vi.fn(async () => ({
      page: [ticket],
      isDone: false,
      continueCursor: "cursor-next",
    }))

    const queues = new Map<string, Doc<"queues">>([
      ["queue_1", { _id: "queue_1" as Id<"queues">, name: "Atendimento", tenantId: TENANT_ID } as Doc<"queues">],
    ])

    const ctx = createCtx({ machine, queues, paginate })

    const result = await listTicketsHistoryHandler(ctx, {
      machineId: machine._id,
      paginationOpts: { numItems: 25, cursor: null },
    })

    expect(paginate).toHaveBeenCalledWith({ numItems: 25, cursor: null })
    expect(result.page).toHaveLength(1)
    expect(result.page[0]).toMatchObject({
      id: "ticket_1",
      subject: "Printer offline",
      priority: "HIGH",
      status: "PENDING",
      queue: "Atendimento",
    })
    expect(result.continueCursor).toBe("cursor-next")
  })

  it("applies search filtering over paginated results", async () => {
    const machine = buildMachine()
    const ticketMatches = buildTicket({
      _id: "ticket_match" as Id<"tickets">,
      reference: 44321,
      subject: "Notebook com tela quebrada",
      requesterSnapshot: { name: "Carla", email: "carla@example.com", avatarUrl: undefined, teams: [] },
    })
    const ticketIgnored = buildTicket({
      _id: "ticket_other" as Id<"tickets">,
      subject: "Troca de teclado",
      requesterSnapshot: { name: "Roberto", email: "roberto@example.com", avatarUrl: undefined, teams: [] },
    })

    const paginate = vi.fn(async () => ({
      page: [ticketMatches, ticketIgnored],
      isDone: true,
      continueCursor: "",
    }))

    const ctx = createCtx({ machine, paginate })

    const result = await listTicketsHistoryHandler(ctx, {
      machineId: machine._id,
      search: "notebook",
      paginationOpts: { numItems: 50, cursor: null },
    })

    expect(result.page).toHaveLength(1)
    expect(result.page[0].id).toBe("ticket_match" as Id<"tickets">)
    expect(result.isDone).toBe(true)
  })
})

describe("convex.machines.getTicketsHistoryStats", () => {
  it("aggregates totals across multiple pages respecting open status", async () => {
    const machine = buildMachine()
    const firstPageTicket = buildTicket({
      _id: "ticket_open" as Id<"tickets">,
      status: "AWAITING_ATTENDANCE",
    })
    const secondPageTicket = buildTicket({
      _id: "ticket_resolved" as Id<"tickets">,
      status: "RESOLVED",
    })

    const paginate = vi.fn(async ({ cursor }: { cursor: string | null }) => {
      if (!cursor) {
        return { page: [firstPageTicket], isDone: false, continueCursor: "cursor-1" }
      }
      return { page: [secondPageTicket], isDone: true, continueCursor: "" }
    })

    const ctx = createCtx({ machine, paginate })

    const stats = await getTicketsHistoryStatsHandler(
      ctx as unknown as Parameters<typeof getTicketsHistoryStatsHandler>[0],
      {
        machineId: machine._id,
      }
    )

    expect(stats).toEqual({ total: 2, openCount: 1, resolvedCount: 1 })
    expect(paginate).toHaveBeenCalledTimes(2)
  })

  it("filters results by search term when aggregating", async () => {
    const machine = buildMachine()
    const matchingTicket = buildTicket({
      _id: "ticket_search" as Id<"tickets">,
      subject: "Notebook com lentidão",
    })
    const nonMatchingTicket = buildTicket({
      _id: "ticket_ignored" as Id<"tickets">,
      subject: "Impressora parada",
    })

    const paginate = vi.fn(async ({ cursor }: { cursor: string | null }) => {
      if (!cursor) {
        return { page: [matchingTicket, nonMatchingTicket], isDone: true, continueCursor: "" }
      }
      return { page: [], isDone: true, continueCursor: "" }
    })

    const ctx = createCtx({ machine, paginate })

    const stats = await getTicketsHistoryStatsHandler(
      ctx as unknown as Parameters<typeof getTicketsHistoryStatsHandler>[0],
      {
        machineId: machine._id,
        search: "notebook",
      }
    )

    expect(stats).toEqual({ total: 1, openCount: 1, resolvedCount: 0 })
  })
})
