import type { Config as FakeTimersConfig } from '@sinonjs/fake-timers'
import type { PrettyFormatOptions } from '@vitest/pretty-format'
import type { SnapshotEnvironment, SnapshotUpdateState } from '@vitest/snapshot'
import type { DiffOptions, SerializedDiffOptions } from '@vitest/utils/diff'
import type { LabelColor } from '../types/general'
import type {
  SequenceHooks,
  SequenceSetupFiles,
  SerializableRetry,
  TestTagDefinition,
} from './runner/types'

/**
 * Config that tests have access to.
 */
export interface SerializedConfig {
  root: string
  setupFiles: string[]
  name: string | undefined
  passWithNoTests: boolean
  testNamePattern: RegExp | undefined
  allowOnly: boolean
  sequence: {
    shuffle?: boolean
    concurrent?: boolean
    seed: number
    hooks: SequenceHooks
    setupFiles: SequenceSetupFiles
  }
  maxConcurrency: number
  testTimeout: number
  hookTimeout: number
  retry: SerializableRetry
  repeats?: number
  includeTaskLocation: boolean | undefined
  tags: TestTagDefinition[]
  tagsFilter: string[] | undefined
  strictTags: boolean
  /**
   * @internal
   */
  _diffOptions?: DiffOptions
  color?: LabelColor
  globals: boolean
  injectCjsGlobals: boolean
  base: string | undefined
  snapshotEnvironment?: string
  disableConsoleIntercept: boolean | undefined
  runner: string | undefined
  isolate: boolean
  maxWorkers: number
  bail: number | undefined
  environmentOptions?: Record<string, any>
  clearMocks: boolean
  mockReset: boolean
  restoreMocks: boolean
  unstubGlobals: boolean
  unstubEnvs: boolean
  // TODO: make optional
  fakeTimers: FakeTimersConfig
  defines: Record<string, any>
  expect: {
    requireAssertions?: boolean
    poll?: {
      timeout?: number
      interval?: number
    }
  }
  printConsoleTrace: boolean | undefined
  deps: {
    web: {
      transformAssets?: boolean
      transformCss?: boolean
      transformGlobPattern?: RegExp | RegExp[]
    }
    optimizer: Record<string, { enabled: boolean }>
    interopDefault: boolean | undefined
    moduleDirectories: string[] | undefined
  }
  snapshotOptions: {
    updateSnapshot: SnapshotUpdateState
    expand: boolean | undefined
    snapshotFormat: PrettyFormatOptions | undefined
    /**
     * only exists for tests, not available in the main process
     */
    snapshotEnvironment: SnapshotEnvironment
  }
  pool: string
  snapshotSerializers: string[]
  chaiConfig: {
    includeStack?: boolean
    showDiff?: boolean
    truncateThreshold?: number
  } | undefined
  taskTitleValueFormatTruncate: number
  api: {
    allowExec: boolean | undefined
    allowWrite: boolean | undefined
  }
  diff: string | SerializedDiffOptions | undefined
  inspect: boolean | string | undefined
  inspectBrk: boolean | string | undefined
  inspector: {
    enabled?: boolean
    port?: number
    host?: string
    waitForDebugger?: boolean
  }
  watch: boolean
  env: Record<string, any>
  browser: {
    name: string
    headless: boolean
    ui: boolean
    viewport: {
      width: number
      height: number
    }
    locators: {
      testIdAttribute: string
      exact: boolean
      errorFormat: 'html' | 'aria' | 'all'
    }
    screenshotFailures: boolean
    providerOptions: {
      // for playwright
      actionTimeout?: number
    }
    trace: BrowserTraceViewMode
    traceView: {
      enabled: boolean
      recordCanvas: boolean
      inlineImages: boolean
    }
    trackUnhandledErrors: boolean
    detailsPanelPosition: 'right' | 'bottom'
  }
  standalone: boolean
  logHeapUsage: boolean | undefined
  detectAsyncLeaks: boolean
  coverage: SerializedCoverageConfig
  benchmark: {
    enabled: boolean
    retainSamples: boolean
    provider: string | undefined
    suppressExportGetterWarnings: boolean
    projectName: string
  }
  serializedDefines: string
  fsModuleCache: boolean
  experimental: {
    importDurations: {
      print: boolean | 'on-warn'
      limit: number
      failOnDanger: boolean
      thresholds: {
        warn: number
        danger: number
      }
    }
    viteModuleRunner: boolean
    nodeLoader: boolean
    openTelemetry: {
      enabled: boolean
      sdkPath?: string
      browserSdkPath?: string
    } | undefined
  }
  mergeReportsLabel: string | undefined
  slowTestThreshold: number | undefined
  disableColors: boolean
}

export interface SerializedCoverageConfig {
  provider: 'istanbul' | 'v8' | 'custom' | undefined
  reportsDirectory: string
  /** Directory where workers write raw coverage results, shard-aware */
  coverageFilesDirectory: string
  htmlDir: string | undefined
  enabled: boolean
  customProviderModule: string | undefined
  autoAttachSubprocess: boolean
}

export interface SerializedRootConfig extends SerializedConfig {
  projects: SerializedConfig[]
}

export type RuntimeConfig = Pick<
  SerializedConfig,
  | 'allowOnly'
  | 'testTimeout'
  | 'hookTimeout'
  | 'clearMocks'
  | 'mockReset'
  | 'restoreMocks'
  | 'fakeTimers'
  | 'maxConcurrency'
  | 'expect'
  | 'printConsoleTrace'
> & {
  sequence?: {
    hooks?: SequenceHooks
  }
}

export type RuntimeOptions = Partial<RuntimeConfig>
export type BrowserTraceViewMode = 'on' | 'off' | 'on-first-retry' | 'on-all-retries' | 'retain-on-failure'
