import { IsArray, IsBoolean, IsInt, IsObject, IsOptional, IsString, Max, Min, ValidateNested } from 'class-validator';
import { Type } from 'class-transformer';

// ── Poll ──

export class RuntimePollJobsRequestDto {
  @IsString()
  runtimeInstanceId!: string;

  @IsArray()
  @IsString({ each: true })
  supportedJobTypes!: string[];

  @IsOptional()
  @IsInt()
  @Min(1)
  @Max(50)
  limit?: number;

  @IsOptional()
  @IsObject()
  capabilities?: Record<string, unknown>;
}

export class RuntimePollJobsResponseItemDto {
  @IsString()
  id!: string;

  @IsString()
  jobType!: string;

  @IsString()
  targetType!: string;

  @IsString()
  targetId!: string;

  @IsInt()
  priority!: number;

  @IsString()
  snapshotId!: string;

  @IsOptional()
  @IsString()
  promptVersion?: string;

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

export class RuntimePollJobsResponseDto {
  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => RuntimePollJobsResponseItemDto)
  jobs!: RuntimePollJobsResponseItemDto[];
}

// ── Lock ──

export class RuntimeLockJobRequestDto {
  @IsString()
  runtimeInstanceId!: string;
}

export class RuntimeLockJobResponseDto {
  @IsString()
  jobId!: string;

  @IsString()
  status!: string;

  @IsInt()
  lockUntil!: number;
}

// ── Heartbeat ──

export class RuntimeHeartbeatRequestDto {
  @IsString()
  runtimeInstanceId!: string;
}

// ── Snapshot ──

export class RuntimeSnapshotResponseDto {
  @IsString()
  jobId!: string;

  @IsString()
  snapshotId!: string;

  @IsString()
  snapshotVersion!: string;

  @IsObject()
  privacyScope!: Record<string, unknown>;

  @IsOptional()
  @IsObject()
  userProfile?: Record<string, unknown>;

  @IsOptional()
  @IsObject()
  aiSettings?: Record<string, unknown>;

  @IsOptional()
  @IsObject()
  deviceContext?: Record<string, unknown>;

  @IsOptional()
  @IsObject()
  learningBehaviorSummary?: Record<string, unknown>;

  @IsOptional()
  @IsObject()
  materialProgressSummary?: Record<string, unknown>;

  @IsOptional()
  @IsObject()
  contentStructureSummary?: Record<string, unknown>;

  @IsOptional()
  @IsObject()
  behaviorSignals?: Record<string, unknown>;

  @IsOptional()
  @IsObject()
  scoreSignals?: Record<string, unknown>;

  @IsOptional()
  @IsObject()
  constraints?: Record<string, unknown>;

  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  allowedModelFields?: string[];
}

// ── Credential Resolve ──

export class RuntimeResolveCredentialRequestDto {
  @IsString()
  jobId!: string;

  @IsString()
  apiKeyMode!: string;

  @IsOptional()
  @IsString()
  credentialId?: string;

  @IsString()
  provider!: string;
}

export class RuntimeResolveCredentialResponseDto {
  @IsString()
  provider!: string;

  @IsString()
  model!: string;

  @IsOptional()
  @IsString()
  baseUrl?: string;

  @IsString()
  apiKey!: string;

  @IsString()
  apiKeyMode!: string;
}

// ── Submit Result ──

export class RuntimeSubmitResultRequestDto {
  @IsString()
  runtimeInstanceId!: string;

  @IsString()
  schemaVersion!: string;

  @IsString()
  status!: string;

  @IsOptional()
  @IsObject()
  rawOutput?: Record<string, unknown>;

  @IsOptional()
  @IsObject()
  validatedOutput?: Record<string, unknown>;

  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  validationErrors?: string[];

  @IsOptional()
  @IsObject()
  usage?: {
    inputTokens?: number;
    outputTokens?: number;
    totalTokens?: number;
    latencyMs?: number;
    costEstimate?: number;
  };

  @IsInt()
  @Min(0)
  attemptNo!: number;

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

// ── Submit Failure ──

export class RuntimeSubmitFailureRequestDto {
  @IsString()
  runtimeInstanceId!: string;

  @IsString()
  errorCode!: string;

  @IsString()
  errorMessage!: string;

  @IsBoolean()
  retryable!: boolean;

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

// ── Invocation Log ──

export class RuntimeInvocationLogDto {
  @IsString()
  jobId!: string;

  @IsString()
  provider!: string;

  @IsString()
  model!: string;

  @IsString()
  apiKeyMode!: string;

  @IsOptional()
  @IsString()
  credentialId?: string;

  @IsString()
  promptName!: string;

  @IsString()
  promptVersion!: string;

  @IsString()
  outputSchemaVersion!: string;

  @IsInt()
  @Min(0)
  inputTokens!: number;

  @IsInt()
  @Min(0)
  outputTokens!: number;

  @IsInt()
  @Min(0)
  totalTokens!: number;

  @IsInt()
  @Min(0)
  latencyMs!: number;

  @IsOptional()
  @IsInt()
  costEstimate?: number;

  @IsBoolean()
  success!: boolean;

  @IsOptional()
  @IsString()
  errorCode?: string;

  @IsOptional()
  @IsString()
  errorMessage?: string;

  @IsInt()
  @Min(0)
  retryCount!: number;

  @IsString()
  runtimeInstanceId!: string;

  @IsOptional()
  @IsString()
  traceId?: string;

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

export class RuntimeSubmitInvocationLogsRequestDto {
  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => RuntimeInvocationLogDto)
  logs!: RuntimeInvocationLogDto[];
}
