import {
  IsArray,
  IsDateString,
  IsEnum,
  IsIn,
  IsInt,
  IsNumberString,
  IsOptional,
  IsString,
  IsUUID,
  Length,
  Max,
  MaxLength,
  Min,
  ValidateNested,
} from 'class-validator';
import { Type } from 'class-transformer';
import { AiUsageOsPlatform } from '@prisma/client';

export type AiUsageToolLiteral = 'claude-code' | 'codex-cli';
export const AI_USAGE_TOOL_VALUES: AiUsageToolLiteral[] = ['claude-code', 'codex-cli'];

export class IngestionEventDto {
  @IsString() @MaxLength(128) rawMessageId!: string;
  @IsIn(AI_USAGE_TOOL_VALUES) tool!: AiUsageToolLiteral;
  @IsString() @MaxLength(128) sessionId!: string;
  @IsString() projectPath!: string;
  @IsString() @MaxLength(128) model!: string;
  @IsDateString() ts!: string;
  @IsInt() @Min(0) inputTokens!: number;
  @IsInt() @Min(0) outputTokens!: number;
  @IsInt() @Min(0) cacheCreationTokens!: number;
  @IsInt() @Min(0) cacheReadTokens!: number;
  @IsNumberString() estimatedCostUsd!: string;

  // v1.1 富 metadata（全部可空，向后兼容老 agent）
  // 隐私铁律：DTO 不接受任何消息内容 / 工具参数 / 工具输出 字段
  @IsOptional() @IsString() @MaxLength(255) gitBranch?: string;
  @IsOptional() @IsString() @MaxLength(32) agentVersionEvent?: string;
  @IsOptional() @IsString() @MaxLength(64) worktreeLabel?: string;
  @IsOptional() @IsString() @MaxLength(255) cwdBasename?: string;
  @IsOptional() @IsInt() @Min(0) turnIndex?: number;
  @IsOptional() @IsInt() @Min(0) toolUseCount?: number;
  @IsOptional() @IsArray() @IsString({ each: true }) @MaxLength(64, { each: true }) toolNames?: string[];
  @IsOptional() @IsString() @MaxLength(32) stopReason?: string;
  @IsOptional() @IsString() @MaxLength(32) serviceTier?: string;
}

export class IngestionBatchDto {
  @IsArray() @ValidateNested({ each: true }) @Type(() => IngestionEventDto)
  events!: IngestionEventDto[];
}

export class CreateTokenDto {
  @IsString() @Length(1, 64) name!: string;
}

export class RevokeTokenDto {
  @IsOptional() @IsString() @MaxLength(500) reason?: string;
}

export class BlockDeviceDto {
  @IsString() @Length(1, 500) reason!: string;
}

export class UnblockDeviceDto {
  @IsOptional() @IsString() @MaxLength(500) note?: string;
}

export class DashboardQueryDto {
  @IsOptional() @IsString() period?: 'today' | 'week' | 'month' | 'year' | 'last7d' | 'last30d' | 'last90d';
  @IsOptional() @IsDateString() from?: string;
  @IsOptional() @IsDateString() to?: string;
  @IsOptional() @IsString() granularity?: 'day' | 'week' | 'month';
  @IsOptional() @IsString() groupBy?: 'none' | 'tool' | 'model' | 'topUser' | 'user' | 'project';
  @IsOptional() @IsString() by?: 'user' | 'project' | 'tool' | 'model' | 'device';
  @IsOptional() @IsInt() @Min(1) @Max(200) @Type(() => Number) page?: number;
  @IsOptional() @IsInt() @Min(1) @Max(200) @Type(() => Number) pageSize?: number;
}

export class DeviceQueryDto {
  @IsOptional() @IsString() status?: 'all' | 'active' | 'blocked';
  @IsOptional() @IsString() q?: string;
  @IsOptional() @IsEnum(AiUsageOsPlatform) platform?: AiUsageOsPlatform;
  @IsOptional() @IsInt() @Min(1) @Type(() => Number) page?: number;
  @IsOptional() @IsInt() @Min(1) @Max(200) @Type(() => Number) pageSize?: number;
}

export class TokenQueryDto {
  @IsOptional() @IsUUID() userId?: string;
  @IsOptional() @IsString() status?: 'all' | 'active' | 'revoked';
  @IsOptional() @IsInt() @Min(1) @Type(() => Number) page?: number;
  @IsOptional() @IsInt() @Min(1) @Max(200) @Type(() => Number) pageSize?: number;
}
