import { Injectable } from '@nestjs/common';
import { cp, mkdir, readFile, writeFile } from 'fs/promises';
import path from 'path';
import { InspectorService } from '../inspector/inspector.service';
import { InspectionExecutionResult } from '../inspector/inspector.types';
import { InspectionTaskEntity } from '../tasks/inspection-task.entity';
import { AgentRunDto } from './agent.dto';

@Injectable()
export class AgentService {
  constructor(private readonly inspectorService: InspectorService) {}

  isEnabled() {
    return true;
  }

  async health() {
    return {
      ok: true,
      service: 'sentai-agent-service',
      enabled: true,
      mode: 'browser-compat',
      now: new Date().toISOString(),
    };
  }

  async run(dto: AgentRunDto) {
    const runDir = path.resolve(
      process.cwd(),
      'storage',
      'agent-runs',
      dto.runId,
    );
    await mkdir(runDir, { recursive: true });

    const payload = {
      runId: dto.runId,
      instruction: dto.instruction,
      siteUrl: dto.siteUrl ?? null,
      checkpoints: dto.checkpoints ?? [],
      status: 'accepted',
      executor: 'agent-s',
      mode: 'browser-compat',
      summary: 'Agent-S 浏览器兼容模式已接收任务。',
      createdAt: new Date().toISOString(),
    };

    await writeFile(
      path.join(runDir, 'request.json'),
      JSON.stringify(payload, null, 2),
      'utf8',
    );

    return payload;
  }

  async runTask(
    task: Pick<InspectionTaskEntity, 'id' | 'name' | 'siteUrl' | 'stepsJson'>,
    traceId: string,
  ): Promise<InspectionExecutionResult> {
    const baseResult = await this.inspectorService.executeTask(task, traceId);
    const runDir = path.resolve(process.cwd(), 'storage', 'agent-runs', traceId);
    const screenshotsDir = path.join(runDir, 'screenshots');
    await mkdir(screenshotsDir, { recursive: true });

    const screenshotPaths = await this.copyScreenshots(
      traceId,
      baseResult.screenshotPaths,
    );
    const resultJsonUrl = await this.writeAgentResultFile(
      runDir,
      task,
      traceId,
      baseResult,
      screenshotPaths,
    );

    return {
      ...baseResult,
      executor: 'agent-s',
      screenshotPaths,
      evidenceDir: `/agent-runs/${traceId}`,
      resultJsonUrl,
    };
  }

  private async copyScreenshots(traceId: string, screenshotPaths: string[]) {
    const copied: string[] = [];

    for (const screenshotPath of screenshotPaths) {
      const filename = path.basename(screenshotPath);
      const sourcePath = path.resolve(
        process.cwd(),
        'storage',
        'runs',
        traceId,
        'screenshots',
        filename,
      );
      const targetPath = path.resolve(
        process.cwd(),
        'storage',
        'agent-runs',
        traceId,
        'screenshots',
        filename,
      );

      await cp(sourcePath, targetPath);
      copied.push(`/agent-runs/${traceId}/screenshots/${filename}`);
    }

    return copied;
  }

  private async writeAgentResultFile(
    runDir: string,
    task: Pick<InspectionTaskEntity, 'id' | 'name' | 'siteUrl'>,
    traceId: string,
    result: InspectionExecutionResult,
    screenshotPaths: string[],
  ) {
    const browserResultPath = path.resolve(
      process.cwd(),
      'storage',
      'runs',
      traceId,
      'result.json',
    );

    let browserResult: Record<string, unknown> | null = null;
    try {
      browserResult = JSON.parse(
        await readFile(browserResultPath, 'utf8'),
      ) as Record<string, unknown>;
    } catch {
      browserResult = null;
    }

    const output = {
      runId: traceId,
      executor: 'agent-s',
      mode: 'browser-compat',
      task,
      status: result.status,
      errorTag: result.errorTag,
      failureReason: result.failureReason,
      pageUrl: result.pageUrl,
      domSummary: result.domSummary,
      screenshots: screenshotPaths,
      stepLogs: result.stepLogs,
      browserDelegate: browserResult,
      generatedAt: new Date().toISOString(),
    };

    await writeFile(
      path.join(runDir, 'result.json'),
      JSON.stringify(output, null, 2),
      'utf8',
    );

    return `/agent-runs/${traceId}/result.json`;
  }
}
