import { formatScreenshotDiffText, formatSnapshotDiffText } from '../../utils/output.ts';
import { AppError } from '../../kernel/errors.ts';
import { isNonDefaultResponseLevel } from '../../kernel/contracts.ts';
import { resolveUserPath } from '../../utils/path-resolution.ts';
import type { AgentDeviceBackend } from '../../backend.ts';
import type { AgentDeviceClient, CaptureScreenshotResult } from '../../client/client.ts';
import { runCliCommand } from '../../commands/cli-runner.ts';
import { pickScreenshotResultData } from '../../utils/screenshot-result.ts';
import type { CliFlags } from '../parser/cli-flags.ts';
import { writeCommandOutput } from './shared.ts';
import type { ClientCommandHandler } from './router-types.ts';

export const screenshotCommand: ClientCommandHandler = async ({ positionals, flags, client }) => {
  const result = (await runCliCommand({
    client,
    command: 'screenshot',
    positionals,
    flags,
  })) as CaptureScreenshotResult;
  // A non-default responseLevel returns a leveled (digest) payload — overlayCount,
  // artifacts, leveled overlayRefs. Rebuilding the default { path, overlayRefs }
  // shape would drop those, so emit the leveled payload verbatim.
  if (isNonDefaultResponseLevel(flags.responseLevel)) {
    writeCommandOutput(flags, result, () => JSON.stringify(result, null, 2));
    return true;
  }
  const data = pickScreenshotResultData(result);
  writeCommandOutput(flags, data, () =>
    result.overlayRefs
      ? `Annotated ${result.overlayRefs.length} refs onto ${result.path}`
      : formatScreenshotSummary(result),
  );
  return true;
};

export const diffCommand: ClientCommandHandler = async ({ positionals, flags, client }) => {
  if (positionals[0] === 'snapshot') {
    const result = await runCliCommand({ client, command: 'diff', positionals, flags });
    writeCommandOutput(flags, result, () => formatSnapshotDiffText(result));
    return true;
  }

  if (positionals[0] !== 'screenshot') return false;

  const baselineRaw = flags.baseline;
  if (!baselineRaw || typeof baselineRaw !== 'string') {
    throw new AppError('INVALID_ARGS', 'diff screenshot requires --baseline <path>');
  }

  const baselinePath = resolveUserPath(baselineRaw);
  const outputPath = typeof flags.out === 'string' ? resolveUserPath(flags.out) : undefined;
  const currentRaw = positionals[1];
  if (positionals.length > 2) {
    throw new AppError(
      'INVALID_ARGS',
      'diff screenshot accepts at most one current screenshot path',
    );
  }

  // Lazy: createAgentDevice pulls the whole client-side command runtime
  // (including screenshot pixel diffing), which only `diff screenshot` needs.
  const [{ createAgentDevice, localCommandPolicy }, { createLocalArtifactAdapter }] =
    await Promise.all([import('../../runtime.ts'), import('../../io.ts')]);
  const runtime = createAgentDevice({
    backend: createClientScreenshotBackend(client, flags),
    artifacts: createLocalArtifactAdapter(),
    sessions: {
      get: (name) => ({ name }),
      set: () => {},
    },
    policy: localCommandPolicy(),
  });

  const result = await runtime.capture.diffScreenshot({
    session: flags.session,
    baseline: { kind: 'path', path: baselinePath },
    current: currentRaw ? { kind: 'path', path: resolveUserPath(currentRaw) } : { kind: 'live' },
    ...(outputPath ? { out: { kind: 'path', path: outputPath } } : {}),
    threshold: parseCliThreshold(flags.threshold),
    overlayRefs: flags.overlayRefs,
    normalizeStatusBar: flags.screenshotNormalizeStatusBar,
    surface: flags.surface,
  });

  writeCommandOutput(flags, result, () => formatScreenshotDiffText(result));
  return true;
};

function createClientScreenshotBackend(
  client: AgentDeviceClient,
  flags: CliFlags,
): AgentDeviceBackend {
  return {
    platform: resolveClientBackendPlatform(flags),
    captureScreenshot: async (context, outPath, options) => {
      const result = await client.capture.screenshot({
        path: outPath,
        session: context.session,
        overlayRefs: options?.overlayRefs,
        pixelDensity: options?.pixelDensity,
        fullscreen: options?.fullscreen,
        normalizeStatusBar: options?.normalizeStatusBar,
        stabilize: options?.stabilize,
        surface: options?.surface,
      });
      return pickScreenshotResultData(result);
    },
  };
}

function formatScreenshotSummary(result: CaptureScreenshotResult): string {
  if (typeof result.width !== 'number' || typeof result.height !== 'number') {
    return result.path;
  }
  const densitySuffix = typeof result.pixelDensity === 'number' ? ` @${result.pixelDensity}x` : '';
  return `${result.path} (${result.width}x${result.height}${densitySuffix})`;
}

function resolveClientBackendPlatform(flags: CliFlags): AgentDeviceBackend['platform'] {
  switch (flags.platform) {
    case 'android':
    case 'linux':
    case 'macos':
      return flags.platform;
    case 'ios':
    case 'apple':
    default:
      return 'ios';
  }
}

function parseCliThreshold(threshold: string | undefined): number | undefined {
  if (threshold == null || threshold === '') return undefined;
  return Number(threshold);
}
