import { describe, it, expect, vi } from "vitest"

// Mock server-only and excel dependencies so the module loads in jsdom
vi.mock("@/shared/lib/excel", () => ({
  exportToExcel: vi.fn(),
}))
vi.mock("@/shared/lib/utils", () => ({
  formatDateForFile: vi.fn(() => "20260624"),
}))

import {
  mapAuditLogsToRows,
  mapLoginLogsToRows,
  mapDataChangeLogsToRows,
  AUDIT_LOG_COLUMNS,
  LOGIN_LOG_COLUMNS,
  DATA_CHANGE_LOG_COLUMNS,
} from "./export"
import type { AuditLog, LoginLog, DataChangeLog } from "./types"

describe("mapAuditLogsToRows", () => {
  const sampleLog: AuditLog = {
    id: "log-1",
    userId: "user-1",
    userName: "Alice",
    action: "create",
    module: "users",
    targetId: "target-1",
    targetType: "user",
    detail: '{"field":"name"}',
    ipAddress: "192.168.1.1",
    userAgent: "Mozilla/5.0",
    status: "success",
    createdAt: "2026-06-24T00:00:00Z",
  }

  it("should map all fields correctly", () => {
    const rows = mapAuditLogsToRows([sampleLog])
    expect(rows).toHaveLength(1)
    expect(rows[0]).toEqual({
      userId: "user-1",
      userName: "Alice",
      module: "users",
      action: "create",
      targetId: "target-1",
      targetType: "user",
      detail: '{"field":"name"}',
      ipAddress: "192.168.1.1",
      status: "success",
      createdAt: "2026-06-24T00:00:00Z",
    })
  })

  it("should convert null fields to empty strings", () => {
    const logWithNulls: AuditLog = {
      ...sampleLog,
      targetId: null,
      targetType: null,
      detail: null,
      ipAddress: null,
      userAgent: null,
    }
    const rows = mapAuditLogsToRows([logWithNulls])
    expect(rows[0].targetId).toBe("")
    expect(rows[0].targetType).toBe("")
    expect(rows[0].detail).toBe("")
    expect(rows[0].ipAddress).toBe("")
  })

  it("should return empty array for empty input", () => {
    expect(mapAuditLogsToRows([])).toEqual([])
  })

  it("should map multiple items", () => {
    const logs = [sampleLog, { ...sampleLog, id: "log-2", userId: "user-2" }]
    const rows = mapAuditLogsToRows(logs)
    expect(rows).toHaveLength(2)
    expect(rows[0].userId).toBe("user-1")
    expect(rows[1].userId).toBe("user-2")
  })
})

describe("mapLoginLogsToRows", () => {
  const sampleLog: LoginLog = {
    id: "log-1",
    userId: "user-1",
    userEmail: "alice@example.com",
    action: "signin",
    status: "success",
    ipAddress: "192.168.1.1",
    userAgent: "Mozilla/5.0",
    errorMessage: null,
    createdAt: "2026-06-24T00:00:00Z",
  }

  it("should map all fields correctly", () => {
    const rows = mapLoginLogsToRows([sampleLog])
    expect(rows).toHaveLength(1)
    expect(rows[0]).toEqual({
      userId: "user-1",
      userEmail: "alice@example.com",
      action: "signin",
      status: "success",
      ipAddress: "192.168.1.1",
      userAgent: "Mozilla/5.0",
      errorMessage: "",
      createdAt: "2026-06-24T00:00:00Z",
    })
  })

  it("should convert null userId to empty string", () => {
    const logWithNullUserId: LoginLog = {
      ...sampleLog,
      userId: null,
    }
    const rows = mapLoginLogsToRows([logWithNullUserId])
    expect(rows[0].userId).toBe("")
  })

  it("should convert null errorMessage to empty string", () => {
    const logWithError: LoginLog = {
      ...sampleLog,
      errorMessage: "Invalid credentials",
    }
    const rows = mapLoginLogsToRows([logWithError])
    expect(rows[0].errorMessage).toBe("Invalid credentials")
  })
})

describe("mapDataChangeLogsToRows", () => {
  const sampleLog: DataChangeLog = {
    id: "log-1",
    tableName: "users",
    recordId: "rec-1",
    action: "update",
    oldValue: '{"name":"old"}',
    newValue: '{"name":"new"}',
    changedBy: "user-1",
    changedByName: "Alice",
    ipAddress: "192.168.1.1",
    createdAt: "2026-06-24T00:00:00Z",
  }

  it("should map all fields correctly", () => {
    const rows = mapDataChangeLogsToRows([sampleLog])
    expect(rows).toHaveLength(1)
    expect(rows[0]).toEqual({
      tableName: "users",
      recordId: "rec-1",
      action: "update",
      oldValue: '{"name":"old"}',
      newValue: '{"name":"new"}',
      changedBy: "user-1",
      changedByName: "Alice",
      ipAddress: "192.168.1.1",
      createdAt: "2026-06-24T00:00:00Z",
    })
  })

  it("should convert null oldValue/newValue to empty strings", () => {
    const logWithNulls: DataChangeLog = {
      ...sampleLog,
      oldValue: null,
      newValue: null,
      ipAddress: null,
    }
    const rows = mapDataChangeLogsToRows([logWithNulls])
    expect(rows[0].oldValue).toBe("")
    expect(rows[0].newValue).toBe("")
    expect(rows[0].ipAddress).toBe("")
  })
})

describe("column definitions", () => {
  it("AUDIT_LOG_COLUMNS should have all required fields", () => {
    const keys = AUDIT_LOG_COLUMNS.map((c) => c.key)
    expect(keys).toContain("userId")
    expect(keys).toContain("userName")
    expect(keys).toContain("module")
    expect(keys).toContain("action")
    expect(keys).toContain("status")
    expect(keys).toContain("createdAt")
  })

  it("LOGIN_LOG_COLUMNS should have all required fields", () => {
    const keys = LOGIN_LOG_COLUMNS.map((c) => c.key)
    expect(keys).toContain("userId")
    expect(keys).toContain("userEmail")
    expect(keys).toContain("action")
    expect(keys).toContain("status")
  })

  it("DATA_CHANGE_LOG_COLUMNS should have all required fields", () => {
    const keys = DATA_CHANGE_LOG_COLUMNS.map((c) => c.key)
    expect(keys).toContain("tableName")
    expect(keys).toContain("recordId")
    expect(keys).toContain("action")
    expect(keys).toContain("oldValue")
    expect(keys).toContain("newValue")
  })

  it("all columns should have header, key, and width", () => {
    for (const col of [...AUDIT_LOG_COLUMNS, ...LOGIN_LOG_COLUMNS, ...DATA_CHANGE_LOG_COLUMNS]) {
      expect(col.header).toBeTruthy()
      expect(col.key).toBeTruthy()
      expect(col.width).toBeGreaterThan(0)
    }
  })
})
