import { Injectable, Logger, NotFoundException } from "@nestjs/common";
import { PrismaService } from "../prisma/prisma.service";
import { CreateQualityGateDto, UpdateQualityGateDto } from "./dto";
import type { QualityGate as PrismaQualityGate } from "@prisma/client";
import type { QualityGate } from "../quality-orchestrator/interfaces";

/**
 * Default quality gates to seed for new workspaces
 */
const DEFAULT_GATES = [
  {
    name: "Build Check",
    type: "build",
    command: "pnpm build",
    required: true,
    order: 1,
  },
  {
    name: "Lint Check",
    type: "lint",
    command: "pnpm lint",
    required: true,
    order: 2,
  },
  {
    name: "Test Suite",
    type: "test",
    command: "pnpm test",
    required: true,
    order: 3,
  },
  {
    name: "Coverage Check",
    type: "coverage",
    command: "pnpm test:coverage",
    expectedOutput: "85",
    required: false,
    order: 4,
  },
];

/**
 * Service for managing quality gate configurations per workspace
 */
@Injectable()
export class QualityGateConfigService {
  private readonly logger = new Logger(QualityGateConfigService.name);

  constructor(private readonly prisma: PrismaService) {}

  /**
   * Create a quality gate for a workspace
   */
  async create(workspaceId: string, dto: CreateQualityGateDto): Promise<PrismaQualityGate> {
    this.logger.log(`Creating quality gate "${dto.name}" for workspace ${workspaceId}`);

    return this.prisma.qualityGate.create({
      data: {
        workspaceId,
        name: dto.name,
        description: dto.description ?? null,
        type: dto.type,
        command: dto.command ?? null,
        expectedOutput: dto.expectedOutput ?? null,
        isRegex: dto.isRegex ?? false,
        required: dto.required ?? true,
        order: dto.order ?? 0,
        isEnabled: true,
      },
    });
  }

  /**
   * Get all gates for a workspace
   */
  async findAll(workspaceId: string): Promise<PrismaQualityGate[]> {
    this.logger.debug(`Finding all quality gates for workspace ${workspaceId}`);

    return this.prisma.qualityGate.findMany({
      where: { workspaceId },
      orderBy: { order: "asc" },
    });
  }

  /**
   * Get enabled gates ordered by priority
   */
  async findEnabled(workspaceId: string): Promise<PrismaQualityGate[]> {
    this.logger.debug(`Finding enabled quality gates for workspace ${workspaceId}`);

    return this.prisma.qualityGate.findMany({
      where: {
        workspaceId,
        isEnabled: true,
      },
      orderBy: { order: "asc" },
    });
  }

  /**
   * Get a specific gate
   */
  async findOne(workspaceId: string, id: string): Promise<PrismaQualityGate> {
    this.logger.debug(`Finding quality gate ${id} for workspace ${workspaceId}`);

    const gate = await this.prisma.qualityGate.findUnique({
      where: {
        id,
        workspaceId,
      },
    });

    if (!gate) {
      throw new NotFoundException(`Quality gate with ID ${id} not found`);
    }

    return gate;
  }

  /**
   * Update a gate
   */
  async update(
    workspaceId: string,
    id: string,
    dto: UpdateQualityGateDto
  ): Promise<PrismaQualityGate> {
    this.logger.log(`Updating quality gate ${id} for workspace ${workspaceId}`);

    // Verify gate exists and belongs to workspace
    await this.findOne(workspaceId, id);

    return this.prisma.qualityGate.update({
      where: { id },
      data: dto,
    });
  }

  /**
   * Delete a gate
   */
  async delete(workspaceId: string, id: string): Promise<void> {
    this.logger.log(`Deleting quality gate ${id} for workspace ${workspaceId}`);

    // Verify gate exists and belongs to workspace
    await this.findOne(workspaceId, id);

    await this.prisma.qualityGate.delete({
      where: { id },
    });
  }

  /**
   * Reorder gates
   */
  async reorder(workspaceId: string, gateIds: string[]): Promise<PrismaQualityGate[]> {
    this.logger.log(`Reordering quality gates for workspace ${workspaceId}`);

    await this.prisma.$transaction(async (tx) => {
      for (let i = 0; i < gateIds.length; i++) {
        const gateId = gateIds[i];
        if (!gateId) continue;

        await tx.qualityGate.update({
          where: { id: gateId },
          data: { order: i },
        });
      }
    });

    return this.findAll(workspaceId);
  }

  /**
   * Seed default gates for a workspace
   */
  async seedDefaults(workspaceId: string): Promise<PrismaQualityGate[]> {
    this.logger.log(`Seeding default quality gates for workspace ${workspaceId}`);

    await this.prisma.$transaction(async (tx) => {
      for (const gate of DEFAULT_GATES) {
        await tx.qualityGate.create({
          data: {
            workspaceId,
            name: gate.name,
            type: gate.type,
            command: gate.command,
            expectedOutput: gate.expectedOutput ?? null,
            required: gate.required,
            order: gate.order,
            isEnabled: true,
          },
        });
      }
    });

    return this.findAll(workspaceId);
  }

  /**
   * Convert database gates to orchestrator format
   */
  toOrchestratorFormat(gates: PrismaQualityGate[]): QualityGate[] {
    return gates.map((gate) => {
      const result: QualityGate = {
        id: gate.id,
        name: gate.name,
        description: gate.description ?? "",
        type: gate.type as "test" | "lint" | "build" | "coverage" | "custom",
        required: gate.required,
        order: gate.order,
      };

      // Only add optional properties if they exist
      if (gate.command) {
        result.command = gate.command;
      }

      if (gate.expectedOutput) {
        if (gate.isRegex) {
          // Safe regex construction with try-catch - pattern is from trusted database source
          try {
            // eslint-disable-next-line security/detect-non-literal-regexp
            result.expectedOutput = new RegExp(gate.expectedOutput);
          } catch {
            this.logger.warn(`Invalid regex pattern for gate ${gate.id}: ${gate.expectedOutput}`);
            result.expectedOutput = gate.expectedOutput;
          }
        } else {
          result.expectedOutput = gate.expectedOutput;
        }
      }

      return result;
    });
  }
}
