import "tsconfig-paths/register"
import { vi } from "bun:test"
import { JSDOM } from "jsdom"

// Provide default environment variables expected across the test suite.
process.env.BETTER_AUTH_SECRET ??= "test-secret"
process.env.NEXT_PUBLIC_APP_URL ??= "http://localhost:3000"
process.env.BETTER_AUTH_URL ??= process.env.NEXT_PUBLIC_APP_URL
process.env.DATABASE_URL ??= "postgresql://postgres:postgres@localhost:5432/sistema_test?schema=public"
process.env.NODE_ENV ??= "test"

const OriginalDate = Date
let fixedTimestamp: number | null = null

type ExtendedVi = typeof vi & {
  mocked?: typeof vi.mocked
  setSystemTime?: typeof vi.setSystemTime
  useFakeTimers?: typeof vi.useFakeTimers
  useRealTimers?: typeof vi.useRealTimers
}

const viExtended = vi as ExtendedVi

if (typeof window === "undefined" || typeof document === "undefined") {
  const dom = new JSDOM("<!DOCTYPE html><html><body></body></html>", {
    url: process.env.NEXT_PUBLIC_APP_URL,
  })
  const globals = dom.window as unknown as Record<string, unknown>
  const globalTarget = globalThis as Record<string, unknown>
  for (const key of ["window", "document", "navigator", "HTMLElement", "HTMLAnchorElement", "Node", "Text"]) {
    if (!(key in globalTarget)) {
      globalTarget[key] = globals[key]
    }
  }
}

const globalTarget = globalThis as Record<string, unknown>
if (typeof globalTarget.Element === "undefined") {
  const win = globalTarget.window as undefined | { Element?: unknown }
  if (win?.Element) {
    globalTarget.Element = win.Element
  }
}

const applyFixedDate = () => {
  if (fixedTimestamp === null) {
    globalThis.Date = OriginalDate
    return
  }

  const ts = fixedTimestamp
  class MockDate extends OriginalDate {
    constructor(...args: ConstructorParameters<typeof OriginalDate>) {
      if (args.length < 1) {
        super(ts)
        return
      }
      super(...args)
    }

    static now(): number {
      return ts
    }
  }

  globalThis.Date = MockDate as unknown as DateConstructor
}

if (!viExtended.mocked) {
  viExtended.mocked = ((item: unknown) => item) as typeof vi.mocked
}

if (!viExtended.setSystemTime) {
  viExtended.setSystemTime = ((value: string | number | Date) => {
    if (typeof value === "string") {
      const parsed = Date.parse(value)
      fixedTimestamp = Number.isFinite(parsed) ? parsed : Date.now()
    } else {
      fixedTimestamp = value instanceof Date ? value.getTime() : value
    }
    applyFixedDate()
    return viExtended
  }) as typeof vi.setSystemTime
}

if (!viExtended.useFakeTimers) {
  viExtended.useFakeTimers = ((..._args: Parameters<typeof vi.useFakeTimers>) => {
    return viExtended
  }) as typeof vi.useFakeTimers
} else {
  const originalUseFakeTimers = viExtended.useFakeTimers.bind(vi)
  viExtended.useFakeTimers = ((...args: Parameters<typeof vi.useFakeTimers>) => {
    const result = originalUseFakeTimers(...args)
    return result ?? viExtended
  }) as typeof vi.useFakeTimers
}

if (!viExtended.useRealTimers) {
  viExtended.useRealTimers = ((..._args: Parameters<typeof vi.useRealTimers>) => {
    fixedTimestamp = null
    applyFixedDate()
    return viExtended
  }) as typeof vi.useRealTimers
} else {
  const originalUseRealTimers = viExtended.useRealTimers.bind(vi)
  viExtended.useRealTimers = ((...args: Parameters<typeof vi.useRealTimers>) => {
    const result = originalUseRealTimers(...args)
    fixedTimestamp = null
    applyFixedDate()
    return result ?? viExtended
  }) as typeof vi.useRealTimers
}

applyFixedDate()
