import type { AuthAdapter, HeaderBuilder, HttpSuiteConfig } from "../index";

export interface LocalDatabaseConfig {
  provider: "local";
  binding?: "shared" | "per-runtime";
  image?: string;
  password?: string;
  reset?: boolean;
  template?: {
    inputs?: string[];
    migrate?: TemplateLifecycleStepConfig[];
    seed?: TemplateLifecycleStepConfig[];
    verify?: TemplateLifecycleStepConfig[];
  };
  user?: string;
}

export interface TemplateStepBaseConfig {
  cwd?: string;
  inputs?: string[];
}

export interface TemplateCommandStepConfig extends TemplateStepBaseConfig {
  kind: "command";
  cmd: string;
}

export interface TemplateSqlFileStepConfig extends TemplateStepBaseConfig {
  kind: "sql-file";
  path: string;
}

export interface TemplateModuleStepConfig extends TemplateStepBaseConfig {
  kind: "module";
  specifier: string;
}

export type TemplateLifecycleStepConfig =
  | TemplateCommandStepConfig
  | TemplateSqlFileStepConfig
  | TemplateModuleStepConfig;

export interface SkipFileRule {
  path: string;
  reason: string;
}

export interface SkipSuiteRule {
  selector: string;
  reason: string;
}

export interface SkipConfig {
  files?: SkipFileRule[];
  suites?: SkipSuiteRule[];
}

export interface RuntimeConfig {
  instances?: number;
  maxConcurrentTasks?: number;
  prepare?: {
    inputs?: string[];
    steps?: TemplateLifecycleStepConfig[];
  };
}

export interface SuiteRequirementRule {
  selector: string;
  locks?: string[];
}

export interface FileRequirementRule {
  path: string;
  locks?: string[];
}

export interface ServiceRequirementConfig {
  suites?: SuiteRequirementRule[];
  files?: FileRequirementRule[];
}

export interface TestkitExecutionConfig {
  workers?: number;
  fileTimeoutSeconds?: number;
}

export interface KnownFailureIssueValidationConfig {
  provider?: "github";
  mode?: "off" | "warn" | "error";
  cacheTtlSeconds?: number;
}

export interface ServiceConfig {
  database?: LocalDatabaseConfig;
  databaseFrom?: string;
  dependsOn?: string[];
  discovery?: {
    roots?: string[];
  };
  env?: Record<string, string>;
  envFile?: string;
  envFiles?: string[];
  local?: false | {
    baseUrl: string;
    cwd?: string;
    env?: Record<string, string>;
    port?: number;
    readyTimeoutMs?: number;
    readyUrl: string;
    start: string;
  };
  runtime?: RuntimeConfig;
  requirements?: ServiceRequirementConfig;
  skip?: SkipConfig;
}

export interface TestkitSetup {
  execution?: TestkitExecutionConfig;
  profiles?: {
    http?: Record<string, HttpSuiteConfig>;
  };
  reporting?: {
    knownFailuresFile?: string;
    issueValidation?: KnownFailureIssueValidationConfig;
  };
  services?: Record<string, ServiceConfig>;
  telemetry?: {
    enabled?: boolean;
    endpoint?: string;
    timeoutMs?: number;
    tokenEnv?: string;
  };
}

export declare function defineTestkitSetup<T extends TestkitSetup>(setup: T): T;
export declare function defineHttpProfile<T extends HttpSuiteConfig>(profile: T): T;
export declare function service<T extends ServiceConfig>(config: T): T;
export declare function localDatabase(options?: Omit<LocalDatabaseConfig, "provider">): LocalDatabaseConfig;
export declare function commandStep(
  cmd: string,
  options?: Omit<TemplateCommandStepConfig, "kind" | "cmd">
): TemplateCommandStepConfig;
export declare function sqlFileStep(
  filePath: string,
  options?: Omit<TemplateSqlFileStepConfig, "kind" | "path">
): TemplateSqlFileStepConfig;
export declare function moduleStep(
  specifier: string,
  options?: Omit<TemplateModuleStepConfig, "kind" | "specifier">
): TemplateModuleStepConfig;
export declare function goService(options: ServiceConfig["local"] & {
  command?: string;
  entrypoint?: string;
  envFiles?: string[];
  readyPath?: string;
}): ServiceConfig;
export declare function nextService(options: ServiceConfig["local"] & {
  envFiles?: string[];
}): ServiceConfig;
export declare function tsxService(options: ServiceConfig["local"] & {
  entry?: string;
  envFiles?: string[];
  readyPath?: string;
}): ServiceConfig;
export declare function clerkSessionProfile(options?: {
  apiBase?: string;
  needsAuth?: boolean;
  secretKeyEnv?: string;
}): HttpSuiteConfig;
export declare function jsonSessionProfile(options?: {
  body?: (context: { env: Record<string, string> }) => unknown;
  cookieName?: string;
  headers?: Record<string, string>;
  loginPath?: string;
  passwordEnv?: string;
  successStatus?: number;
  usernameEnv?: string;
}): HttpSuiteConfig;

export declare function registerRepoSetup(setup: unknown): void;
export declare function getRepoSetup(): unknown;
export declare function clearRepoSetup(): void;
export declare function registerRuntimeContext(context: unknown): void;
export declare function getRuntimeContext(): unknown;
export declare function clearRuntimeContext(): void;
export declare const runtimeHttp: {
  del(url: string, body?: unknown, params?: unknown): unknown;
  file(data: unknown, filename?: string, contentType?: string): unknown;
  get(url: string, params?: unknown): unknown;
  patch(url: string, body?: unknown, params?: unknown): unknown;
  post(url: string, body?: unknown, params?: unknown): unknown;
  put(url: string, body?: unknown, params?: unknown): unknown;
};
export declare function runtimeJson<T = unknown>(response: { body: string }): T;
