import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '@chatapp/database';

@Injectable()
export class WorkflowExecutionsService {
  constructor(private readonly prisma: PrismaService) {}

  /**
   * Lista las ejecuciones de un workflow con paginación.
   * Filtra por workspace indirectamente validando que el workflow pertenece al workspace.
   */
  async listExecutions(
    workspaceId: string,
    workflowId: string,
    opts: { status?: string; page?: number; limit?: number } = {},
  ) {
    const workflow = await this.prisma.workflow.findFirst({
      where: { id: workflowId, workspaceId },
      select: { id: true },
    });
    if (!workflow) throw new NotFoundException('Workflow not found');

    const page = Math.max(1, opts.page || 1);
    const limit = Math.min(100, Math.max(1, opts.limit || 20));
    const where: any = { workflowId };
    if (opts.status) where.status = opts.status;

    const [items, total] = await Promise.all([
      this.prisma.workflowExecution.findMany({
        where,
        orderBy: { startedAt: 'desc' },
        skip: (page - 1) * limit,
        take: limit,
      }),
      this.prisma.workflowExecution.count({ where }),
    ]);

    return {
      items,
      total,
      page,
      limit,
      totalPages: Math.ceil(total / limit),
    };
  }

  /**
   * Obtiene el detalle completo de una ejecución específica.
   */
  async getExecution(workspaceId: string, executionId: string) {
    const execution = await this.prisma.workflowExecution.findUnique({
      where: { id: executionId },
      include: { workflow: { select: { id: true, name: true, workspaceId: true } } },
    });
    if (!execution) throw new NotFoundException('Execution not found');
    if (execution.workflow.workspaceId !== workspaceId) {
      throw new NotFoundException('Execution not found');
    }
    return execution;
  }

  /**
   * Cancela una ejecución en estado 'running'.
   */
  async cancelExecution(workspaceId: string, executionId: string) {
    const execution = await this.prisma.workflowExecution.findUnique({
      where: { id: executionId },
      include: { workflow: { select: { workspaceId: true } } },
    });
    if (!execution) throw new NotFoundException('Execution not found');
    if (execution.workflow.workspaceId !== workspaceId) {
      throw new NotFoundException('Execution not found');
    }
    if (execution.status !== 'running') {
      return execution;
    }
    return this.prisma.workflowExecution.update({
      where: { id: executionId },
      data: { status: 'cancelled', completedAt: new Date(), errorMessage: 'Cancelled by user' },
    });
  }

  /**
   * Reintenta una ejecución fallida o cancelada creando una nueva ejecución
   * del mismo workflow con los mismos triggerData.
   */
  async retryExecution(workspaceId: string, executionId: string) {
    const execution = await this.prisma.workflowExecution.findUnique({
      where: { id: executionId },
      include: { workflow: { select: { workspaceId: true, id: true, status: true, steps: true } } },
    });
    if (!execution) throw new NotFoundException('Execution not found');
    if (execution.workflow.workspaceId !== workspaceId) {
      throw new NotFoundException('Execution not found');
    }
    if (execution.workflow.status !== 'active') {
      throw new NotFoundException('Workflow is not active');
    }

    const triggerData = (execution.triggerData ?? {}) as any;
    const newExecution = await this.prisma.workflowExecution.create({
      data: {
        workflowId: execution.workflowId,
        status: 'pending',
        triggerData,
        startedAt: new Date(),
      },
    });

    return { executionId: newExecution.id, status: 'pending', originalExecutionId: executionId };
  }

  /**
   * Obtiene estadísticas de ejecuciones de un workflow.
   */
  async getExecutionStats(workspaceId: string, workflowId: string) {
    const workflow = await this.prisma.workflow.findFirst({
      where: { id: workflowId, workspaceId },
      select: { id: true },
    });
    if (!workflow) throw new NotFoundException('Workflow not found');

    const [total, running, completed, failed, cancelled] = await Promise.all([
      this.prisma.workflowExecution.count({ where: { workflowId } }),
      this.prisma.workflowExecution.count({ where: { workflowId, status: 'running' } }),
      this.prisma.workflowExecution.count({ where: { workflowId, status: 'completed' } }),
      this.prisma.workflowExecution.count({ where: { workflowId, status: 'failed' } }),
      this.prisma.workflowExecution.count({ where: { workflowId, status: 'cancelled' } }),
    ]);

    const successRate = total > 0 ? Math.round((completed / total) * 100) : 0;

    return { total, running, completed, failed, cancelled, successRate };
  }
}