import { Injectable } from "@nestjs/common";
import { AgentStatus, ProjectStatus, RunnerJobStatus, TaskStatus } from "@prisma/client";
import { PrismaService } from "../prisma/prisma.service";
import type {
  DashboardSummaryDto,
  ActiveJobDto,
  RecentActivityDto,
  TokenBudgetEntryDto,
} from "./dto";

/**
 * Service for aggregating dashboard summary data.
 * Executes all queries in parallel to minimize latency.
 */
@Injectable()
export class DashboardService {
  constructor(private readonly prisma: PrismaService) {}

  /**
   * Get aggregated dashboard summary for a workspace
   */
  async getSummary(workspaceId: string): Promise<DashboardSummaryDto> {
    const now = new Date();
    const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000);

    // Execute all queries in parallel
    const [
      activeAgents,
      tasksCompleted,
      totalTasks,
      tasksInProgress,
      activeProjects,
      failedJobsLast24h,
      totalJobsLast24h,
      recentActivityRows,
      activeJobRows,
      tokenBudgetRows,
    ] = await Promise.all([
      // Active agents: IDLE, WORKING, WAITING
      this.prisma.agent.count({
        where: {
          workspaceId,
          status: { in: [AgentStatus.IDLE, AgentStatus.WORKING, AgentStatus.WAITING] },
        },
      }),

      // Tasks completed
      this.prisma.task.count({
        where: {
          workspaceId,
          status: TaskStatus.COMPLETED,
        },
      }),

      // Total tasks
      this.prisma.task.count({
        where: { workspaceId },
      }),

      // Tasks in progress
      this.prisma.task.count({
        where: {
          workspaceId,
          status: TaskStatus.IN_PROGRESS,
        },
      }),

      // Active projects
      this.prisma.project.count({
        where: {
          workspaceId,
          status: ProjectStatus.ACTIVE,
        },
      }),

      // Failed jobs in last 24h (for error rate)
      this.prisma.runnerJob.count({
        where: {
          workspaceId,
          status: RunnerJobStatus.FAILED,
          createdAt: { gte: oneDayAgo },
        },
      }),

      // Total jobs in last 24h (for error rate)
      this.prisma.runnerJob.count({
        where: {
          workspaceId,
          createdAt: { gte: oneDayAgo },
        },
      }),

      // Recent activity: last 10 entries
      this.prisma.activityLog.findMany({
        where: { workspaceId },
        orderBy: { createdAt: "desc" },
        take: 10,
      }),

      // Active jobs: PENDING, QUEUED, RUNNING with steps
      this.prisma.runnerJob.findMany({
        where: {
          workspaceId,
          status: {
            in: [RunnerJobStatus.PENDING, RunnerJobStatus.QUEUED, RunnerJobStatus.RUNNING],
          },
        },
        include: {
          steps: {
            select: {
              id: true,
              name: true,
              status: true,
              phase: true,
            },
            orderBy: { ordinal: "asc" },
          },
        },
        orderBy: { createdAt: "desc" },
      }),

      // Token budgets for workspace (active, not yet completed)
      this.prisma.tokenBudget.findMany({
        where: {
          workspaceId,
          completedAt: null,
        },
        select: {
          agentId: true,
          totalTokensUsed: true,
          allocatedTokens: true,
        },
      }),
    ]);

    // Compute error rate
    const errorRate = totalJobsLast24h > 0 ? (failedJobsLast24h / totalJobsLast24h) * 100 : 0;

    // Map recent activity
    const recentActivity: RecentActivityDto[] = recentActivityRows.map((row) => ({
      id: row.id,
      action: row.action,
      entityType: row.entityType,
      entityId: row.entityId,
      details: row.details as Record<string, unknown> | null,
      userId: row.userId,
      createdAt: row.createdAt.toISOString(),
    }));

    // Map active jobs (RunnerJob lacks updatedAt; use startedAt or createdAt as proxy)
    const activeJobs: ActiveJobDto[] = activeJobRows.map((row) => ({
      id: row.id,
      type: row.type,
      status: row.status,
      progressPercent: row.progressPercent,
      createdAt: row.createdAt.toISOString(),
      updatedAt: (row.startedAt ?? row.createdAt).toISOString(),
      steps: row.steps.map((step) => ({
        id: step.id,
        name: step.name,
        status: step.status,
        phase: step.phase,
      })),
    }));

    // Map token budget entries
    const tokenBudget: TokenBudgetEntryDto[] = tokenBudgetRows.map((row) => ({
      model: row.agentId,
      used: row.totalTokensUsed,
      limit: row.allocatedTokens,
    }));

    return {
      metrics: {
        activeAgents,
        tasksCompleted,
        totalTasks,
        tasksInProgress,
        activeProjects,
        errorRate: Math.round(errorRate * 100) / 100,
      },
      recentActivity,
      activeJobs,
      tokenBudget,
    };
  }
}
