import {
  IsString,
  IsNotEmpty,
  IsEnum,
  ValidateNested,
  IsArray,
  IsOptional,
  ArrayNotEmpty,
  ArrayMaxSize,
  MaxLength,
  IsIn,
  Validate,
  ValidatorConstraint,
  ValidatorConstraintInterface,
  ValidationArguments,
} from "class-validator";
import { Type } from "class-transformer";
import { AgentType } from "../../../spawner/types/agent-spawner.types";
import { GateProfileType } from "../../../coordinator/types/gate-config.types";
import { validateBranchName, validateRepositoryUrl } from "../../../git/git-validation.util";

/**
 * Custom validator for git branch names
 * Uses whitelist-based validation to prevent command injection
 */
@ValidatorConstraint({ name: "isValidBranchName", async: false })
export class IsValidBranchName implements ValidatorConstraintInterface {
  validate(branchName: string, _args: ValidationArguments): boolean {
    try {
      validateBranchName(branchName);
      return true;
    } catch {
      return false;
    }
  }

  defaultMessage(args: ValidationArguments): string {
    try {
      validateBranchName(args.value as string);
      return "Branch name is invalid";
    } catch (error) {
      return error instanceof Error ? error.message : "Branch name is invalid";
    }
  }
}

/**
 * Custom validator for git repository URLs
 * Prevents SSRF and command injection via dangerous protocols
 */
@ValidatorConstraint({ name: "isValidRepositoryUrl", async: false })
export class IsValidRepositoryUrl implements ValidatorConstraintInterface {
  validate(repositoryUrl: string, _args: ValidationArguments): boolean {
    try {
      validateRepositoryUrl(repositoryUrl);
      return true;
    } catch {
      return false;
    }
  }

  defaultMessage(args: ValidationArguments): string {
    try {
      validateRepositoryUrl(args.value as string);
      return "Repository URL is invalid";
    } catch (error) {
      return error instanceof Error ? error.message : "Repository URL is invalid";
    }
  }
}

/**
 * Context DTO for agent spawn request
 */
export class AgentContextDto {
  @IsString()
  @IsNotEmpty()
  @Validate(IsValidRepositoryUrl)
  repository!: string;

  @IsString()
  @IsNotEmpty()
  @Validate(IsValidBranchName)
  branch!: string;

  @IsArray()
  @ArrayNotEmpty()
  @ArrayMaxSize(50, { message: "workItems must contain at most 50 items" })
  @IsString({ each: true })
  @MaxLength(2000, { each: true, message: "Each work item must be at most 2000 characters" })
  workItems!: string[];

  @IsArray()
  @IsOptional()
  @ArrayMaxSize(20, { message: "skills must contain at most 20 items" })
  @IsString({ each: true })
  @MaxLength(200, { each: true, message: "Each skill must be at most 200 characters" })
  skills?: string[];
}

/**
 * Request DTO for spawning an agent
 */
export class SpawnAgentDto {
  @IsString()
  @IsNotEmpty()
  taskId!: string;

  @IsEnum(["worker", "reviewer", "tester"])
  agentType!: AgentType;

  @ValidateNested()
  @Type(() => AgentContextDto)
  context!: AgentContextDto;

  @IsOptional()
  @IsIn(["strict", "standard", "minimal", "custom"])
  gateProfile?: GateProfileType;

  @IsOptional()
  @IsString()
  parentAgentId?: string;
}

/**
 * Response DTO for spawn agent endpoint
 */
export class SpawnAgentResponseDto {
  agentId!: string;
  status!: "spawning" | "queued";
}
