/**
 * Canonical type contract for JavaScript executed by Repeato Script steps and
 * advanced configuration hooks.
 *
 * Keep the website mirror and documentation in sync as described in AGENTS.md.
 */

interface ScreenRegion {
  x: number
  y: number
  width: number
  height: number
}

interface Step {
  id: string
  type: string
  tags: string[]
  optional: boolean
  hasTag(tag: string): boolean
}

interface DeviceData {
  os: string
  abi: string
  sdk: string
  osVersion: string
  size: string
  baseSize: string
  serial: string
  name: string
  brand: string
  currentRotation: string
}

interface StepResult {
  step: Step
  success: boolean
  message: string
  scannedText: string
  screenshot: string
  createdOn: string
  setMessage(message: string): void
}

interface TestRun {
  id: string
  date: string
  completed: boolean
  stepResults: StepResult[]
  deviceData: DeviceData
  duration: number
  appStartupDuration: number
  skippedFramesCount: number
  wasSuccessful: boolean
  getStepResultByStepId(stepId: string): StepResult
  getScreenshotPathByStepId(stepId: string): string
  getSuccessfulStepResults(): StepResult[]
}

interface Test {
  id: string
  title: string
  description: string
  steps: Step[]
  deviceData: DeviceData
  createdOn: string
  changedOn: string
  testRuns: TestRun[]
  lastStep: Step
  getStepById(stepId: string): Step
  getLatestTestRun(): TestRun
}

interface TestBatchExceptionHandler {
  id: string
  test: Test
  afterFinish: unknown
}

interface TestBatch {
  id: string
  title: string
  tests: Test[]
  exceptionHandlers: TestBatchExceptionHandler[]
  createdOn: string
  changedOn: string
}

interface BatchRunStats {
  totalCount: number
  successCount: number
  failCount: number
  duration: number
  stepsCount: number
}

interface BatchRun {
  id: string
  title: string
  batchId: string
  tests: Test[]
  testRuns: TestRun[]
  createdOn: string
  stats: BatchRunStats
  wasSuccessful: boolean
}

interface DeviceConnector {
  /** Data for the currently connected device. */
  selectedDeviceData: DeviceData

  /** Sends text to the currently focused input field. */
  sendString(value: string): Promise<void>

  /** Clears the currently focused input field. */
  clearText(): Promise<void>

  /** Taps normalized screen coordinates between 0 and 1. */
  sendClick(xPercentage: number, yPercentage: number): Promise<void>

  /** Starts a gesture at normalized screen coordinates between 0 and 1. */
  sendDown(xPercentage: number, yPercentage: number): Promise<void>

  /** Moves an active gesture to normalized screen coordinates between 0 and 1. */
  sendMove(xPercentage: number, yPercentage: number): Promise<void>

  /** Finishes a gesture at normalized screen coordinates between 0 and 1. */
  sendUp(xPercentage: number, yPercentage: number): Promise<void>

  /** Runs an ADB command. Not available for iOS or cloud devices. */
  sendAdbCommand(command: string): Promise<string>

  /** Registers a listener for log lines emitted by the app under test. */
  addOnDeviceLog(listenerName: string, callback: (log: string) => void): void

  /** Runs an IDB command against the selected iOS device or simulator. */
  sendIdbCommand(command: string): Promise<string>

  /** Saves the current device frame to an absolute file path. */
  takeScreenshot(filepath: string): Promise<void>

  /** Replaces the device clipboard content. */
  setClipboard(content: string): Promise<void>

  /** Returns the current device clipboard content. */
  getClipboard(): Promise<string>

  /** Sends a screenshot and prompt to Repeato Vision. */
  vision(prompt: string, region?: ScreenRegion): Promise<string>
}

interface TestRunner {
  currentTest: Test
  currentTestRun: TestRun
  lastStepResult: StepResult
  currentStepIndex: number

  /** Selects the next step by ID. */
  setNextStepId(id: string): void

  /** Selects the next step by its zero-based index. */
  setNextStepIndex(index: number): void

  /** Moves execution back by the given number of steps. */
  goBackBy(stepCount: number): void

  addOnScreenshotSaved(
    key: string,
    listener: (stepResult: StepResult, screenshotPath: string) => void
  ): void
  addOnStepCompleted(key: string, callback: (stepResult: StepResult) => void): void
  removeOnScreenshotSaved(key: string): void
  removeOnStepCompleted(key: string): void
  setScaleInvariantMatchingEnabled(enabled: boolean): void
}

type BatchRunMode = 'AllTests' | 'OnlyFailed'

interface BatchRunner {
  testBatch: TestBatch
  currentExceptionHandlerIndex: number
  currentTestIndex: number
  batchRun: BatchRun
  isPlaying: boolean
  runMode: BatchRunMode
  testRunner: TestRunner

  stop(): Promise<void>
  createBatchRunExport(): Promise<string>
  uploadReport(dirPath: string): Promise<string>
  setTestBatchById(batchId: string): void
  setRunMode(mode: BatchRunMode): void
  addOnBatchStart(key: string, callback: (batch: TestBatch) => void): void
  addOnTestFail(
    key: string,
    callback: (test: Test, testRun: TestRun, stepResult: StepResult) => void
  ): void
  addOnTestSuccess(key: string, callback: (test: Test, testRun: TestRun) => void): void
  addOnBatchCompleted(key: string, callback: (batchRun: BatchRun) => void): void
  removeOnBatchStart(key: string): void
  removeOnTestFail(key: string): void
  removeOnTestSuccess(key: string): void
  removeOnBatchCompleted(key: string): void
}

interface AudioTools {
  /** Speaks text using the operating system's speech synthesis. */
  say(text: string): void

  /** Plays audio and resolves when playback finishes. */
  playAudio(url: string): Promise<number>

  /** Stops the current audio playback. */
  stopAudio(): void

  /** Records microphone audio and resolves with a temporary object URL. */
  recordAudio(duration: number): Promise<string>
}

interface SharedData {
  scannedText: string
  [key: string]: unknown
}

interface RepeatoDialog {
  cancel(): void
  confirm(): void
}

interface RepeatoDialogOptions {
  title: string
  content: string
  onConfirm?: () => void
  onClose?: () => void
}

/** Values shared between Script steps in the current test run. */
declare const data: SharedData

declare const workspaceDir: string
declare const currentStepIndex: number
declare const testDir: string
declare const testRunDir: string
declare const testRunner: TestRunner
declare const deviceConnector: DeviceConnector
declare const batchRunner: BatchRunner
declare const audioTools: AudioTools
declare const axios: import('axios').AxiosStatic

declare function log(message: unknown, ...additionalValues: unknown[]): void
declare function sleep(milliseconds: number): Promise<void>
declare function getResponse(host: string, path: string, headers?: object): Promise<string>
declare function sendPost(
  host: string,
  path: string,
  body: string | object,
  acceptHeader?: string,
  headers?: object
): Promise<string>
declare function showDialog(options: RepeatoDialogOptions): RepeatoDialog
