import { Controller, Get, Post, Param, Body, UseGuards } from '@nestjs/common';
import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger';
import { InjectQueue } from '@nestjs/bullmq';
import { Queue, Job } from 'bullmq';
import { PrismaService } from '../../infrastructure/database/prisma.service';
import { WorkerHeartbeat } from '../../infrastructure/queue/worker-heartbeat';
import { AdminAuthGuard } from '../../common/guards/admin-auth.guard';
import { AdminRolesGuard } from '../../common/guards/admin-roles.guard';
import { AdminRoles } from '../../common/decorators/admin-roles.decorator';
import { getAllTaskConfigs } from '../../infrastructure/queue/task-types';
import type { AdminRole } from '../../common/types/admin-role.enum';

const QUEUES = ['ai-analysis', 'document-import', 'notification', 'domain-events', 'audit-logs', 'file-cleanup'] as const;

@ApiTags('admin-events')
@Controller('admin-api/events')
@UseGuards(AdminAuthGuard, AdminRolesGuard)
@ApiBearerAuth()
export class AdminEventsController {
  constructor(
    private readonly heartbeat: WorkerHeartbeat,
    private readonly prisma: PrismaService,
    @InjectQueue('ai-analysis') private aiQ: Queue,
    @InjectQueue('document-import') private importQ: Queue,
    @InjectQueue('notification') private notifyQ: Queue,
    @InjectQueue('domain-events') private eventQ: Queue,
  ) {}

  @Get()
  @AdminRoles('SUPER_ADMIN' as AdminRole)
  @ApiOperation({ summary: '队列概览' })
  async overview() {
    const queues = await Promise.all(
      QUEUES.map(async (name) => {
        const q = this.getQueue(name);
        const [waiting, active, completed, failed, delayed] = await Promise.all([
          q.getWaitingCount(), q.getActiveCount(), q.getCompletedCount(),
          q.getFailedCount(), q.getDelayedCount(),
        ]);
        return { name, waiting, active, completed, failed, delayed, total: waiting + active + completed + failed + delayed };
      }),
    );
    const workers = await this.heartbeat.getActiveWorkers();
    return { queues, workers };
  }

  // ── Task statistics dashboard ──

  @Get('stats')
  @AdminRoles('SUPER_ADMIN' as AdminRole)
  @ApiOperation({ summary: '任务统计 Dashboard' })
  async stats() {
    const taskConfigs = getAllTaskConfigs();

    // Failure stats from TaskLog (DB)
    const recentFailures = await this.prisma.taskLog.groupBy({
      by: ['queueName'],
      where: { status: { in: ['failed', 'error'] }, createdAt: { gte: new Date(Date.now() - 7 * 86400000) } },
      _count: { id: true },
    });

    const failMap: Record<string, number> = {};
    for (const f of recentFailures) {
      failMap[f.queueName] = f._count.id;
    }

    const taskStats = taskConfigs.map(c => ({
      type: c.type,
      label: c.label,
      maxRetries: c.maxRetries,
      timeoutMs: c.timeoutMs,
      failureCount7d: failMap[c.type] || 0,
    }));

    return { taskStats, totalTaskTypes: taskConfigs.length };
  }

  // ── Worker status ──

  @Get('workers')
  @AdminRoles('SUPER_ADMIN' as AdminRole)
  @ApiOperation({ summary: 'Worker 节点状态' })
  async workers() {
    const workers = await this.heartbeat.getActiveWorkers();
    return { workers, count: workers.length };
  }

  // ── Failed jobs ──

  @Get(':queue/failed')
  @AdminRoles('SUPER_ADMIN' as AdminRole)
  @ApiOperation({ summary: '失败任务列表' })
  async failed(@Param('queue') queueName: string) {
    const q = this.getQueue(queueName);
    const jobs = await q.getFailed(0, 20);
    return { jobs: jobs.map(this.formatJob) };
  }

  @Get(':queue/jobs/:jobId')
  @AdminRoles('SUPER_ADMIN' as AdminRole)
  @ApiOperation({ summary: '任务详情' })
  async jobDetail(@Param('queue') queueName: string, @Param('jobId') jobId: string) {
    const q = this.getQueue(queueName);
    const job = await q.getJob(jobId);
    if (!job) return { error: 'Job not found' };
    const state = await job.getState();
    return { ...this.formatJob(job), state, data: job.data, stacktrace: job.stacktrace };
  }

  @Post(':queue/jobs/:jobId/retry')
  @AdminRoles('SUPER_ADMIN' as AdminRole)
  @ApiOperation({ summary: '重试失败任务' })
  async retry(@Param('queue') queueName: string, @Param('jobId') jobId: string) {
    const q = this.getQueue(queueName);
    const job = await q.getJob(jobId);
    if (!job) return { error: 'Job not found' };
    await job.retry();
    await this.prisma.adminAuditLog.create({
      data: { adminUserId: 'system', action: 'TASK_RETRY', resourceType: 'TaskLog', resourceId: jobId },
    }).catch(() => {});
    await this.prisma.taskLog.updateMany({
      where: { jobId }, data: { status: 'retried', updatedAt: new Date() },
    }).catch(() => {});
    return { success: true };
  }

  @Post(':queue/jobs/batch-retry')
  @AdminRoles('SUPER_ADMIN' as AdminRole)
  @ApiOperation({ summary: '批量重试失败任务' })
  async batchRetry(@Param('queue') queueName: string, @Body() body: { count?: number }) {
    const q = this.getQueue(queueName);
    const failedJobs = await q.getFailed(0, body.count || 50);
    let retried = 0;
    for (const job of failedJobs) {
      try {
        await job.retry();
        await this.prisma.adminAuditLog.create({
          data: { adminUserId: 'system', action: 'TASK_BATCH_RETRY', resourceType: 'TaskLog', resourceId: job.id || '' },
        }).catch(() => {});
        retried++;
      } catch {
        // skip unrecoverable jobs
      }
    }
    return { success: true, retried, total: failedJobs.length };
  }

  private getQueue(name: string): Queue {
    const map: Record<string, Queue> = {
      'ai-analysis': this.aiQ, 'document-import': this.importQ,
      'notification': this.notifyQ, 'domain-events': this.eventQ,
    };
    return map[name] || this.eventQ;
  }

  private formatJob(job: Job) {
    return {
      id: job.id, name: job.name, timestamp: job.timestamp,
      attemptsMade: job.attemptsMade, failedReason: job.failedReason?.slice(0, 200),
      finishedOn: job.finishedOn, processedOn: job.processedOn,
    };
  }
}
