import { Injectable } from "@nestjs/common";
import {
  GateProfile,
  GateProfileType,
  GateRequirements,
  GateSelection,
  TaskGateConfig,
} from "./types/gate-config.types";

/**
 * Service for managing quality gate configurations per task
 *
 * Provides predefined gate profiles and custom gate configuration:
 * - Strict: All gates enabled (for reviewer agents, critical code)
 * - Standard: Core gates (typecheck, lint, tests, coverage) (for worker agents)
 * - Minimal: Tests only (for tester agents, documentation)
 * - Custom: User-defined gate selection
 *
 * Different agent types have different default profiles:
 * - Worker: Standard profile
 * - Reviewer: Strict profile
 * - Tester: Minimal profile
 */
@Injectable()
export class GateConfigService {
  /**
   * Get default gate profile for agent type
   *
   * @param agentType Agent type (worker, reviewer, tester)
   * @returns Default gate profile for the agent type
   */
  getDefaultProfile(agentType: "worker" | "reviewer" | "tester"): GateProfile {
    switch (agentType) {
      case "reviewer":
        return this.getProfileByName("strict");
      case "worker":
        return this.getProfileByName("standard");
      case "tester":
        return this.getProfileByName("minimal");
    }
  }

  /**
   * Get predefined gate profile by name
   *
   * @param profileName Profile name (strict, standard, minimal, custom)
   * @returns Gate profile configuration
   * @throws Error if profile name is invalid
   */
  getProfileByName(profileName: GateProfileType): GateProfile {
    switch (profileName) {
      case "strict":
        return {
          name: "strict",
          gates: {
            typecheck: true,
            lint: true,
            tests: true,
            coverage: { enabled: true, threshold: 85 },
            build: true,
            integration: true,
            aiReview: true,
          },
        };

      case "standard":
        return {
          name: "standard",
          gates: {
            typecheck: true,
            lint: true,
            tests: true,
            coverage: { enabled: true, threshold: 85 },
          },
        };

      case "minimal":
        return {
          name: "minimal",
          gates: {
            tests: true,
          },
        };

      case "custom":
        return {
          name: "custom",
          gates: {},
        };

      default:
        throw new Error(`Invalid profile name: ${String(profileName)}`);
    }
  }

  /**
   * Create task gate configuration
   *
   * @param taskId Task ID
   * @param agentType Agent type
   * @param profileName Optional profile name (defaults to agent's default profile)
   * @param customGates Optional custom gate selection (required for custom profile)
   * @returns Task gate configuration
   * @throws Error if custom profile specified without gates
   */
  createTaskConfig(
    taskId: string,
    agentType: "worker" | "reviewer" | "tester",
    profileName?: GateProfileType,
    customGates?: GateSelection
  ): TaskGateConfig {
    let profile: GateProfile;

    if (profileName === "custom") {
      if (!customGates) {
        throw new Error("Custom profile requires gate selection");
      }
      this.validateGateSelection(customGates);
      profile = {
        name: "custom",
        gates: customGates,
      };
    } else if (profileName) {
      profile = this.getProfileByName(profileName);
    } else {
      profile = this.getDefaultProfile(agentType);
    }

    return {
      taskId,
      agentType,
      profile,
    };
  }

  /**
   * Get gate requirements from task configuration
   *
   * Extracts gate requirements for quality check requests to coordinator.
   *
   * @param config Task gate configuration
   * @returns Gate requirements for coordinator
   */
  getGateRequirements(config: TaskGateConfig): GateRequirements {
    return {
      gates: config.profile.gates,
      metadata: {
        profile: config.profile.name,
        agentType: config.agentType,
      },
    };
  }

  /**
   * Validate gate selection
   *
   * Ensures:
   * - At least one gate is enabled
   * - Coverage threshold is valid (0-100)
   *
   * @param gates Gate selection to validate
   * @throws Error if validation fails
   */
  validateGateSelection(gates: GateSelection): void {
    // Check if at least one gate is enabled
    const hasEnabledGate =
      gates.typecheck === true ||
      gates.lint === true ||
      gates.tests === true ||
      gates.coverage?.enabled === true ||
      gates.build === true ||
      gates.integration === true ||
      gates.aiReview === true;

    if (!hasEnabledGate) {
      throw new Error("At least one gate must be enabled");
    }

    // Validate coverage threshold if specified
    if (gates.coverage?.threshold !== undefined) {
      if (gates.coverage.threshold < 0 || gates.coverage.threshold > 100) {
        throw new Error("Coverage threshold must be between 0 and 100");
      }
    }
  }

  /**
   * Merge two gate selections
   *
   * Override values take precedence over base values.
   *
   * @param base Base gate selection
   * @param override Override gate selection
   * @returns Merged gate selection
   */
  mergeGateSelections(base: GateSelection, override: GateSelection): GateSelection {
    return {
      ...base,
      ...override,
    };
  }
}
