import {
  IsString,
  IsObject,
  IsOptional,
  IsEnum,
  IsInt,
  Min,
  Max,
  IsArray,
  IsBoolean,
  IsUUID,
  ValidateNested,
  IsDateString,
  IsNumber,
  IsNotEmpty,
  IsIn,
} from 'class-validator';
import { Type, Transform } from 'class-transformer';

// ==================== 附件 ====================

export class AttachmentDto {
  @IsString()
  id: string;

  @IsString()
  name: string;

  @IsString()
  url: string;

  @IsNumber()
  size: number;

  @IsString()
  mimeType: string;
}

// ==================== 流程启动 ====================

export class StartApprovalDto {
  @IsString()
  processDefinitionKey: string; // 流程定义 KEY

  @IsString()
  businessType: string; // 业务类型

  @IsString()
  businessId: string; // 业务单据 ID

  @IsOptional()
  @IsObject()
  variables?: Record<string, any>; // 流程变量

  @IsOptional()
  @IsString()
  title?: string; // 标题

  @IsOptional()
  @IsInt()
  @Min(0)
  @Max(3)
  priority?: number; // 优先级

  @IsOptional()
  @IsDateString()
  dueDate?: string; // 截止时间

  @IsOptional()
  @IsInt()
  version?: number; // 指定版本

  @IsOptional()
  @IsString()
  callbackUrl?: string; // 回调 URL

  @IsOptional()
  @IsString()
  idempotencyKey?: string; // 幂等键
}

// ==================== 审批操作 ====================

export class ApproveDto {
  @IsString()
  @IsNotEmpty()
  taskId: string;

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

  @IsOptional()
  @IsObject()
  formData?: Record<string, any>; // 审批人可修改的表单数据

  @IsOptional()
  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => AttachmentDto)
  attachments?: AttachmentDto[];
}

export class RejectDto {
  @IsString()
  @IsUUID()
  taskId: string;

  @IsString()
  comment: string; // 驳回理由（必填）

  @IsOptional()
  @IsString()
  rejectCode?: string; // 驳回代码（用于统计）

  @IsOptional()
  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => AttachmentDto)
  attachments?: AttachmentDto[];
}

export class ReturnDto {
  @IsString()
  @IsUUID()
  taskId: string;

  @IsString()
  targetNodeId: string; // 退回到的目标节点 ID

  @IsString()
  comment: string; // 退回理由（必填）
}

export class ForwardDto {
  @IsString()
  @IsUUID()
  taskId: string;

  @IsString()
  @IsUUID()
  toUserId: string; // 转发给谁

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

export class WithdrawDto {
  @IsOptional()
  @IsString()
  reason?: string;
}

export class ApproverWithdrawDto {
  @IsString()
  @IsUUID()
  taskId: string;

  @IsString()
  reason: string; // 撤回理由（必填）
}

export class AddSignDto {
  @IsString()
  @IsUUID()
  taskId: string;

  @IsArray()
  @IsString({ each: true })
  userIds: string[]; // 加签人列表

  @IsEnum(['BEFORE', 'AFTER', 'PARALLEL'])
  type: 'BEFORE' | 'AFTER' | 'PARALLEL';

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

export class ClaimDto {
  @IsString()
  @IsUUID()
  taskId: string;
}

export class UnclaimDto {
  @IsString()
  @IsUUID()
  taskId: string;
}

export class ExecuteDto {
  @IsString()
  @IsUUID()
  taskId: string;

  @IsObject()
  formData: Record<string, any>;

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

  @IsOptional()
  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => AttachmentDto)
  attachments?: AttachmentDto[];
}

// ==================== 任务查询 ====================

export class PendingTasksQueryDto {
  @IsOptional()
  @IsString()
  businessType?: string;

  @IsOptional()
  @IsEnum(['PENDING', 'CLAIMED'])
  status?: 'PENDING' | 'CLAIMED';

  @IsOptional()
  @IsInt()
  @Min(0)
  @Max(3)
  priority?: number;

  @IsOptional()
  @IsBoolean()
  @Transform(({ value }) => value === 'true' || value === true)
  isOverdue?: boolean;

  @IsOptional()
  @IsBoolean()
  @Transform(({ value }) => value === 'true' || value === true)
  isDelegated?: boolean;

  @IsOptional()
  @IsEnum(['createTime', 'dueDate', 'priority', 'lastReminderTime', 'remainingHours'])
  sortBy?: 'createTime' | 'dueDate' | 'priority' | 'lastReminderTime' | 'remainingHours';

  @IsOptional()
  @IsEnum(['asc', 'desc'])
  sortOrder?: 'asc' | 'desc';

  @IsOptional()
  @IsInt()
  @Min(1)
  @Transform(({ value }) => parseInt(value) || 1)
  page?: number = 1;

  @IsOptional()
  @IsInt()
  @Min(1)
  @Max(100)
  @Transform(({ value }) => parseInt(value) || 20)
  limit?: number = 20;
}

export class InitiatedQueryDto {
  @IsOptional()
  @IsString()
  businessType?: string;

  @IsOptional()
  @IsEnum(['RUNNING', 'APPROVED', 'REJECTED', 'WITHDRAWN', 'TERMINATED', 'SUSPENDED'])
  status?: string;

  @IsOptional()
  @IsDateString()
  startTimeFrom?: string;

  @IsOptional()
  @IsDateString()
  startTimeTo?: string;

  @IsOptional()
  @IsInt()
  @Min(1)
  @Transform(({ value }) => parseInt(value) || 1)
  page?: number = 1;

  @IsOptional()
  @IsInt()
  @Min(1)
  @Max(100)
  @Transform(({ value }) => parseInt(value) || 20)
  limit?: number = 20;
}

// ==================== 管理员数据中心 ====================

export class AdminAnalyticsQueryDto {
  @IsOptional()
  @IsString()
  formKey?: string;

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

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

  @IsOptional()
  @IsBoolean()
  @Transform(({ value, obj }) => {
    const rawValue = obj?.approvalRequired ?? value;
    if (rawValue === undefined || rawValue === null || rawValue === '') {
      return undefined;
    }
    if (rawValue === 'true' || rawValue === true) {
      return true;
    }
    if (rawValue === 'false' || rawValue === false) {
      return false;
    }
    return value;
  })
  approvalRequired?: boolean;

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

  @IsOptional()
  @IsDateString()
  timeFrom?: string;

  @IsOptional()
  @IsDateString()
  timeTo?: string;

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

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

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

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

export class AdminInstancesQueryDto extends AdminAnalyticsQueryDto {
  @IsOptional()
  @IsInt()
  @Min(1)
  @Transform(({ value }) => parseInt(value) || 1)
  page?: number = 1;

  @IsOptional()
  @IsInt()
  @Min(1)
  @Max(200)
  @Transform(({ value }) => parseInt(value) || 20)
  limit?: number = 20;
}

export class AdminInstancesExportDto extends AdminAnalyticsQueryDto {
  @IsOptional()
  @IsIn(['xlsx', 'csv'])
  format?: 'xlsx' | 'csv' = 'xlsx';
}

export class AdminSettingsDto {
  @IsInt()
  @Min(7)
  @Max(365)
  exportRetentionDays: number;
}

export class ProcessedQueryDto {
  @IsOptional()
  @IsString()
  businessType?: string;

  @IsOptional()
  @IsEnum(['APPROVE', 'REJECT', 'RETURN', 'FORWARD'])
  action?: string;

  @IsOptional()
  @IsDateString()
  actionTimeFrom?: string;

  @IsOptional()
  @IsDateString()
  actionTimeTo?: string;

  @IsOptional()
  @IsInt()
  @Min(1)
  @Transform(({ value }) => parseInt(value) || 1)
  page?: number = 1;

  @IsOptional()
  @IsInt()
  @Min(1)
  @Max(100)
  @Transform(({ value }) => parseInt(value) || 20)
  limit?: number = 20;
}

export class CcQueryDto {
  @IsOptional()
  @IsString()
  businessType?: string;

  @IsOptional()
  @IsBoolean()
  @Transform(({ value }) => value === 'true' || value === true)
  isRead?: boolean;

  @IsOptional()
  @IsInt()
  @Min(1)
  @Transform(({ value }) => parseInt(value) || 1)
  page?: number = 1;

  @IsOptional()
  @IsInt()
  @Min(1)
  @Max(100)
  @Transform(({ value }) => parseInt(value) || 20)
  limit?: number = 20;
}

// ==================== 流程查询 ====================

export class ProcessSearchDto {
  @IsOptional()
  @IsString()
  keyword?: string;

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

  @IsOptional()
  @IsEnum(['RUNNING', 'APPROVED', 'REJECTED', 'WITHDRAWN', 'TERMINATED', 'SUSPENDED', 'FAILED'])
  status?: string;

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

  @IsOptional()
  @IsDateString()
  startTimeFrom?: string;

  @IsOptional()
  @IsDateString()
  startTimeTo?: string;

  @IsOptional()
  @IsInt()
  @Min(1)
  @Transform(({ value }) => parseInt(value) || 1)
  page?: number = 1;

  @IsOptional()
  @IsInt()
  @Min(1)
  @Max(100)
  @Transform(({ value }) => parseInt(value) || 20)
  limit?: number = 20;
}

// ==================== 催办 ====================

export class RemindDto {
  @IsString()
  @IsUUID()
  taskId: string;

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

export class BatchRemindDto {
  @IsArray()
  @IsString({ each: true })
  taskIds: string[];

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

// ==================== 流程定义管理 ====================

export class CreateDefinitionDto {
  @IsString()
  key: string;

  @IsString()
  name: string;

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

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

  @IsOptional()
  @IsUUID()
  organizationId?: string;
}

export class UpdateDefinitionDto {
  @IsOptional()
  @IsString()
  name?: string;

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

  @IsOptional()
  @IsEnum(['ACTIVE', 'SUSPENDED', 'ARCHIVED'])
  status?: string;
}

export class DefinitionsQueryDto {
  @IsOptional()
  @IsInt()
  @Min(1)
  @Type(() => Number)
  page?: number = 1;

  @IsOptional()
  @IsInt()
  @Min(1)
  @Max(100)
  @Type(() => Number)
  limit?: number = 20;

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

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

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

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

  @IsOptional()
  @IsString()
  sortOrder?: 'asc' | 'desc';
}

export class CreateVersionDto {
  @IsString()
  name: string;

  @IsObject()
  processModel: Record<string, any>;

  @IsOptional()
  @IsObject()
  settings?: Record<string, any>;

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

export class UpdateVersionDto {
  @IsOptional()
  @IsString()
  name?: string;

  @IsOptional()
  @IsObject()
  processModel?: Record<string, any>;

  @IsOptional()
  @IsObject()
  settings?: Record<string, any>;

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

export class DeployVersionDto {
  @IsOptional()
  @IsBoolean()
  setAsDefault?: boolean = true;
}

// ==================== 管理员操作 ====================

export class AdminTerminateDto {
  @IsString()
  reason: string;

  @IsOptional()
  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => AttachmentDto)
  attachments?: AttachmentDto[];
}

/**
 * 管理员介入挂起的审批流程（ERR-20260501-004 配套）。
 * 节点审批人解析失败导致 SUSPENDED 时，管理员通过此 DTO 显式指派审批人恢复流程。
 */
export class AdminResumeWithApproversDto {
  @IsArray()
  @IsUUID(undefined, { each: true })
  approverIds: string[];

  @IsString()
  reason: string;
}

export class AdminApproveDto {
  @IsString()
  @IsUUID()
  taskId: string;

  @IsString()
  comment: string;

  @IsString()
  reason: string; // 代审批原因（必填）

  @IsOptional()
  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => AttachmentDto)
  attachments?: AttachmentDto[];
}

export class AdminRejectDto {
  @IsString()
  @IsUUID()
  taskId: string;

  @IsString()
  comment: string;

  @IsString()
  reason: string; // 代审批原因（必填）

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

  @IsOptional()
  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => AttachmentDto)
  attachments?: AttachmentDto[];
}

export class AdminReassignDto {
  @IsString()
  @IsUUID()
  taskId: string;

  @IsString()
  @IsUUID()
  newAssigneeId: string;

  @IsString()
  reason: string;
}

export class AuditLogsQueryDto {
  @IsOptional()
  @IsString()
  instanceId?: string;

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

  @IsOptional()
  @IsEnum(['ADMIN_APPROVE', 'ADMIN_REJECT', 'ADMIN_TERMINATE', 'ADMIN_REASSIGN'])
  action?: string;

  @IsOptional()
  @IsEnum(['HIGH', 'MEDIUM', 'LOW'])
  riskLevel?: string;

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

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

  @IsOptional()
  @IsDateString()
  timeFrom?: string;

  @IsOptional()
  @IsDateString()
  timeTo?: string;

  @IsOptional()
  @IsEnum(['actionTime', 'riskLevel'])
  sortBy?: 'actionTime' | 'riskLevel';

  @IsOptional()
  @IsEnum(['asc', 'desc'])
  sortOrder?: 'asc' | 'desc';

  @IsOptional()
  @IsInt()
  @Min(1)
  @Transform(({ value }) => parseInt(value) || 1)
  page?: number = 1;

  @IsOptional()
  @IsInt()
  @Min(1)
  @Max(100)
  @Transform(({ value }) => parseInt(value) || 20)
  limit?: number = 20;
}

// ==================== 兼容旧 DTO（保持向后兼容） ====================

export class QueryApprovalDto {
  @IsOptional()
  @IsString()
  businessType?: string;

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

  @IsOptional()
  @IsInt()
  @Min(1)
  page?: number = 1;

  @IsOptional()
  @IsInt()
  @Min(1)
  @Max(100)
  limit?: number = 20;
}

// 旧版 AddApproverDto（重命名为 AddSignDto）
export class AddApproverDto {
  @IsString()
  taskId: string;

  @IsString()
  addUserId: string;

  @IsEnum(['before', 'after'])
  position: 'before' | 'after';

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