import {
  Body,
  Controller,
  Delete,
  Get,
  Headers,
  Param,
  Patch,
  Post,
  Put,
  Query,
} from '@nestjs/common';
import {
  BuildMonitorAgentPackageDto,
  ClearQueuedMonitorRunsDto,
  CreateMonitorAgentDto,
  CreateMonitorTargetDto,
  DeleteMonitorRunsDto,
  ExecuteMonitorTargetDto,
  RequeueStaleMonitorRunsDto,
  UpdateMonitorAgentDto,
  UpdateMonitorAgentFeaturesDto,
  UpdateMonitorAgentStatusDto,
  UpdateMonitorAlertStatusDto,
  UpdateMonitorTargetDto,
  UpdateMonitorTargetStatusDto,
} from './monitoring.dto';
import { MonitoringSchedulerService } from './monitoring-scheduler.service';
import { MonitoringService } from './monitoring.service';
import { MonitorAlertService } from './monitor-alert.service';
import { Public } from '../auth/public.decorator';

@Controller('/api/monitoring')
export class MonitoringController {
  constructor(
    private readonly monitoringService: MonitoringService,
    private readonly monitoringSchedulerService: MonitoringSchedulerService,
    private readonly monitorAlertService: MonitorAlertService,
  ) {}

  @Get('/summary')
  getSummary() {
    return this.monitoringService.getSummary();
  }

  @Get('/agents')
  getAgents() {
    return this.monitoringService.getAgents();
  }

  @Post('/agents')
  createAgent(@Body() body: CreateMonitorAgentDto) {
    return this.monitoringService.createAgent(body);
  }

  @Put('/agents/:id')
  updateAgent(@Param('id') id: string, @Body() body: UpdateMonitorAgentDto) {
    return this.monitoringService.updateAgent(id, body);
  }

  @Patch('/agents/:id/status')
  updateAgentStatus(
    @Param('id') id: string,
    @Body() body: UpdateMonitorAgentStatusDto,
  ) {
    return this.monitoringService.updateAgentStatus(id, body.status);
  }

  @Patch('/agents/:id/features')
  updateAgentFeatures(
    @Param('id') id: string,
    @Body() body: UpdateMonitorAgentFeaturesDto,
  ) {
    return this.monitoringService.updateAgentFeatures(id, body);
  }

  @Post('/agents/:id/verify')
  verifyAgent(@Param('id') id: string) {
    return this.monitoringService.verifyAgent(id);
  }

  @Post('/agents/:id/package')
  buildAgentPackage(
    @Param('id') id: string,
    @Body() body: BuildMonitorAgentPackageDto,
    @Headers('host') host?: string,
    @Headers('x-forwarded-proto') forwardedProto?: string,
  ) {
    const inferredApiBase = host
      ? `${forwardedProto?.trim() || 'http'}://${host.trim()}`
      : undefined;
    return this.monitoringService.buildAgentPackage(id, {
      ...body,
      requestApiBase: inferredApiBase,
    });
  }

  @Get('/targets')
  getTargets(
    @Query('keyword') keyword?: string,
    @Query('status') status?: 'enabled' | 'disabled',
  ) {
    return this.monitoringService.getTargets({ keyword, status });
  }

  @Post('/targets')
  async createTarget(@Body() body: CreateMonitorTargetDto) {
    this.monitoringSchedulerService.validateCron(body.cronExpr);
    const result = await this.monitoringService.createTarget(body);
    await this.monitoringSchedulerService.syncTarget(result.targetId);
    return result;
  }

  @Put('/targets/:id')
  async updateTarget(
    @Param('id') id: string,
    @Body() body: UpdateMonitorTargetDto,
  ) {
    this.monitoringSchedulerService.validateCron(body.cronExpr);
    const result = await this.monitoringService.updateTarget(id, body);
    await this.monitoringSchedulerService.syncTarget(result.targetId);
    return result;
  }

  @Patch('/targets/:id/status')
  async updateTargetStatus(
    @Param('id') id: string,
    @Body() body: UpdateMonitorTargetStatusDto,
  ) {
    const result = await this.monitoringService.updateTargetStatus(id, body.status);
    await this.monitoringSchedulerService.syncTarget(id);
    return result;
  }

  @Delete('/targets/:id')
  async deleteTarget(@Param('id') id: string) {
    await this.monitoringSchedulerService.removeTarget(id);
    return this.monitoringService.deleteTarget(id);
  }

  @Get('/runs')
  getRuns(
    @Query('targetId') targetId?: string,
    @Query('status')
    status?: 'queued' | 'running' | 'success' | 'failed' | 'partial',
    @Query('limit') limit?: string,
    @Query('latestPerTarget') latestPerTarget?: string,
  ) {
    return this.monitoringService.getRuns({
      targetId,
      status,
      limit: limit ? Number(limit) : undefined,
      latestPerTarget:
        latestPerTarget === '1' || latestPerTarget === 'true',
    });
  }

  @Get('/runs/:runId')
  getRunDetail(@Param('runId') runId: string) {
    return this.monitoringService.getRunDetail(runId);
  }

  @Delete('/runs/:runId')
  deleteRun(@Param('runId') runId: string) {
    return this.monitoringService.deleteRun(runId);
  }

  @Post('/runs/actions/delete')
  deleteRuns(@Body() body: DeleteMonitorRunsDto) {
    return this.monitoringService.deleteRuns(body.runIds);
  }

  @Post('/runs/:runId/requeue')
  requeueRun(@Param('runId') runId: string) {
    return this.monitoringService.requeueRun(runId);
  }

  @Post('/runs/actions/clear-queued')
  clearQueuedRuns(@Body() body: ClearQueuedMonitorRunsDto) {
    return this.monitoringService.clearQueuedRuns(body);
  }

  @Post('/runs/actions/requeue-stale')
  requeueStaleRuns(@Body() body: RequeueStaleMonitorRunsDto) {
    return this.monitoringService.requeueStaleRuns(body);
  }

  @Get('/logs/recent')
  getRecentLogs(@Query('serviceKey') serviceKey: string) {
    return this.monitoringService.getRecentLogs(serviceKey);
  }

  @Get('/alerts')
  getAlerts(
    @Query('status') status?: 'open' | 'acknowledged' | 'resolved',
    @Query('severity') severity?: 'info' | 'warning' | 'major' | 'critical',
    @Query('targetId') targetId?: string,
    @Query('limit') limit?: string,
  ) {
    return this.monitorAlertService.getAlerts({
      status,
      severity,
      targetId,
      limit: limit ? Number(limit) : undefined,
    });
  }

  @Get('/alerts/:alertId')
  getAlertDetail(@Param('alertId') alertId: string) {
    return this.monitorAlertService.getAlertDetail(alertId);
  }

  @Patch('/alerts/:alertId/status')
  updateAlertStatus(
    @Param('alertId') alertId: string,
    @Body() body: UpdateMonitorAlertStatusDto,
  ) {
    return this.monitorAlertService.updateAlertStatus(alertId, body.status);
  }

  @Public()
  @Post('/agent/jobs/claim')
  claimAgentJob(
    @Body() body: { agentKey: string },
    @Headers('x-monitoring-agent-token') agentToken?: string,
  ) {
    return this.monitoringService.claimAgentJob(body.agentKey, agentToken);
  }

  @Public()
  @Post('/agent/heartbeat')
  heartbeat(
    @Body()
    body: {
      agentKey: string;
      host?: string;
      platform?: string;
      version?: string;
      meta?: Record<string, unknown>;
    },
    @Headers('x-monitoring-agent-token') agentToken?: string,
  ) {
    return this.monitoringService.recordAgentHeartbeat(body, agentToken);
  }

  @Public()
  @Post('/agent/jobs/:runId/result')
  submitAgentJobResult(
    @Param('runId') runId: string,
    @Body()
    body: {
      status: 'success' | 'failed' | 'partial';
      errorTag: string | null;
      summary: string;
      failureReason: string | null;
      metrics?: Record<string, unknown>;
      details?: Record<string, unknown>;
      logExcerpt?: string | null;
    },
    @Headers('x-monitoring-agent-token') agentToken?: string,
  ) {
    return this.monitoringService.submitAgentJobResult(runId, body, agentToken);
  }

  @Public()
  @Post('/logs/ingest')
  ingestLogs(
    @Body() body: unknown,
    @Headers('x-monitoring-ingest-token') ingestToken?: string,
  ) {
    return this.monitoringService.ingestLogs(body, ingestToken);
  }

  @Post('/runs/execute/:targetId')
  executeTarget(
    @Param('targetId') targetId: string,
    @Body() body: ExecuteMonitorTargetDto,
  ) {
    return this.monitoringService.executeTarget(targetId, body);
  }
}
