import {
  IsString,
  IsOptional,
  IsNumber,
  IsArray,
  IsDateString,
  IsEnum,
  IsBoolean,
  ValidateNested,
  Min,
  Max,
} from 'class-validator';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { Type } from 'class-transformer';

/**
 * GembaDocs API Types and DTOs
 *
 * GembaDocs is an audit and checklist management system for manufacturing
 * and quality assurance processes (e.g., Layered Process Audits, 5S audits).
 */

// ============ Enums ============

export enum AuditType {
  LAYERED_PROCESS = 'layered_process',
  SAFETY = 'safety',
  FIVE_S = '5s',
  QUALITY = 'quality',
  CUSTOM = 'custom',
}

export enum AuditStatus {
  SCHEDULED = 'scheduled',
  IN_PROGRESS = 'in_progress',
  COMPLETED = 'completed',
  CANCELLED = 'cancelled',
}

export enum FindingSeverity {
  LOW = 'low',
  MEDIUM = 'medium',
  HIGH = 'high',
  CRITICAL = 'critical',
}

export enum FindingStatus {
  OPEN = 'open',
  IN_PROGRESS = 'in_progress',
  RESOLVED = 'resolved',
  VERIFIED = 'verified',
}

export enum ChecklistItemType {
  YES_NO = 'yes_no',
  RATING = 'rating',
  TEXT = 'text',
  PHOTO = 'photo',
}

// ============ API Response Types ============

export interface GembaUser {
  id: string;
  name: string;
  email?: string;
  department?: string;
}

export interface GembaAudit {
  id: string;
  title: string;
  type: AuditType;
  status: AuditStatus;
  scheduledDate: string;
  completedDate?: string;
  auditor: GembaUser;
  department?: string;
  location?: string;
  checklist?: GembaChecklist;
  findings: GembaFinding[];
  score?: number;
  maxScore?: number;
  notes?: string;
  createdAt: string;
  updatedAt: string;
}

export interface GembaChecklist {
  id: string;
  name: string;
  version: string;
  description?: string;
  categories: GembaChecklistCategory[];
  totalItems: number;
  completedItems: number;
  createdAt: string;
  updatedAt: string;
}

export interface GembaChecklistCategory {
  id: string;
  name: string;
  description?: string;
  sortOrder: number;
  items: GembaChecklistItem[];
}

export interface GembaChecklistItem {
  id: string;
  question: string;
  type: ChecklistItemType;
  required: boolean;
  answer?: string | number | boolean | null;
  score?: number;
  maxScore?: number;
  note?: string;
  photoUrl?: string;
  sortOrder: number;
}

export interface GembaFinding {
  id: string;
  auditId: string;
  title: string;
  description: string;
  severity: FindingSeverity;
  status: FindingStatus;
  dueDate?: string;
  assignee?: GembaUser;
  photos: string[];
  correctiveAction?: string;
  rootCause?: string;
  checklistItemId?: string;
  createdAt: string;
  updatedAt: string;
  resolvedAt?: string;
  verifiedAt?: string;
  verifiedBy?: GembaUser;
}

export interface GembaAttachment {
  id: string;
  fileName: string;
  fileSize: number;
  mimeType: string;
  url: string;
  thumbnailUrl?: string;
  uploadedAt: string;
  uploadedBy: GembaUser;
}

export interface GembaStatistics {
  totalAudits: number;
  completedAudits: number;
  scheduledAudits: number;
  overdueAudits: number;
  totalFindings: number;
  openFindings: number;
  resolvedFindings: number;
  averageComplianceScore: number;
  auditsByType: Record<AuditType, number>;
  findingsBySeverity: Record<FindingSeverity, number>;
  findingsByStatus: Record<FindingStatus, number>;
  complianceTrend: GembaComplianceTrendPoint[];
}

export interface GembaComplianceTrendPoint {
  date: string;
  score: number;
  auditCount: number;
}

export interface GembaTrendData {
  period: string;
  startDate: string;
  endDate: string;
  dataPoints: GembaTrendDataPoint[];
}

export interface GembaTrendDataPoint {
  date: string;
  totalAudits: number;
  completedAudits: number;
  complianceScore: number;
  findingsCreated: number;
  findingsResolved: number;
}

export interface GembaApiResponse<T> {
  success: boolean;
  data?: T;
  error?: {
    code: string;
    message: string;
  };
  pagination?: {
    page: number;
    pageSize: number;
    total: number;
    totalPages: number;
  };
}

// ============ Request DTOs ============

export class ListAuditsDto {
  @ApiPropertyOptional({ description: 'Filter by audit type', enum: AuditType })
  @IsOptional()
  @IsEnum(AuditType)
  type?: AuditType;

  @ApiPropertyOptional({ description: 'Filter by audit status', enum: AuditStatus })
  @IsOptional()
  @IsEnum(AuditStatus)
  status?: AuditStatus;

  @ApiPropertyOptional({ description: 'Filter by department' })
  @IsOptional()
  @IsString()
  department?: string;

  @ApiPropertyOptional({ description: 'Filter by location' })
  @IsOptional()
  @IsString()
  location?: string;

  @ApiPropertyOptional({ description: 'Filter by auditor ID' })
  @IsOptional()
  @IsString()
  auditorId?: string;

  @ApiPropertyOptional({ description: 'Start date filter (YYYY-MM-DD)' })
  @IsOptional()
  @IsDateString()
  dateFrom?: string;

  @ApiPropertyOptional({ description: 'End date filter (YYYY-MM-DD)' })
  @IsOptional()
  @IsDateString()
  dateTo?: string;

  @ApiPropertyOptional({ description: 'Page number', default: 1 })
  @IsOptional()
  @IsNumber()
  @Min(1)
  page?: number;

  @ApiPropertyOptional({ description: 'Items per page', default: 20 })
  @IsOptional()
  @IsNumber()
  @Min(1)
  @Max(100)
  pageSize?: number;
}

export class CreateAuditDto {
  @ApiProperty({ description: 'Audit title' })
  @IsString()
  title: string;

  @ApiProperty({ description: 'Audit type', enum: AuditType })
  @IsEnum(AuditType)
  type: AuditType;

  @ApiProperty({ description: 'Scheduled date (YYYY-MM-DD)' })
  @IsDateString()
  scheduledDate: string;

  @ApiProperty({ description: 'Auditor ID' })
  @IsString()
  auditorId: string;

  @ApiPropertyOptional({ description: 'Checklist template ID' })
  @IsOptional()
  @IsString()
  checklistId?: string;

  @ApiPropertyOptional({ description: 'Department' })
  @IsOptional()
  @IsString()
  department?: string;

  @ApiPropertyOptional({ description: 'Location' })
  @IsOptional()
  @IsString()
  location?: string;

  @ApiPropertyOptional({ description: 'Additional notes' })
  @IsOptional()
  @IsString()
  notes?: string;
}

export class UpdateAuditDto {
  @ApiPropertyOptional({ description: 'Audit title' })
  @IsOptional()
  @IsString()
  title?: string;

  @ApiPropertyOptional({ description: 'Audit status', enum: AuditStatus })
  @IsOptional()
  @IsEnum(AuditStatus)
  status?: AuditStatus;

  @ApiPropertyOptional({ description: 'Scheduled date (YYYY-MM-DD)' })
  @IsOptional()
  @IsDateString()
  scheduledDate?: string;

  @ApiPropertyOptional({ description: 'Completed date (YYYY-MM-DD)' })
  @IsOptional()
  @IsDateString()
  completedDate?: string;

  @ApiPropertyOptional({ description: 'Auditor ID' })
  @IsOptional()
  @IsString()
  auditorId?: string;

  @ApiPropertyOptional({ description: 'Department' })
  @IsOptional()
  @IsString()
  department?: string;

  @ApiPropertyOptional({ description: 'Location' })
  @IsOptional()
  @IsString()
  location?: string;

  @ApiPropertyOptional({ description: 'Additional notes' })
  @IsOptional()
  @IsString()
  notes?: string;

  @ApiPropertyOptional({ description: 'Score achieved' })
  @IsOptional()
  @IsNumber()
  @Min(0)
  score?: number;
}

export class ListFindingsDto {
  @ApiPropertyOptional({ description: 'Filter by audit ID' })
  @IsOptional()
  @IsString()
  auditId?: string;

  @ApiPropertyOptional({ description: 'Filter by severity', enum: FindingSeverity })
  @IsOptional()
  @IsEnum(FindingSeverity)
  severity?: FindingSeverity;

  @ApiPropertyOptional({ description: 'Filter by status', enum: FindingStatus })
  @IsOptional()
  @IsEnum(FindingStatus)
  status?: FindingStatus;

  @ApiPropertyOptional({ description: 'Filter by assignee ID' })
  @IsOptional()
  @IsString()
  assigneeId?: string;

  @ApiPropertyOptional({ description: 'Filter overdue findings only' })
  @IsOptional()
  @IsBoolean()
  overdueOnly?: boolean;

  @ApiPropertyOptional({ description: 'Page number', default: 1 })
  @IsOptional()
  @IsNumber()
  @Min(1)
  page?: number;

  @ApiPropertyOptional({ description: 'Items per page', default: 20 })
  @IsOptional()
  @IsNumber()
  @Min(1)
  @Max(100)
  pageSize?: number;
}

export class UpdateFindingDto {
  @ApiPropertyOptional({ description: 'Finding title' })
  @IsOptional()
  @IsString()
  title?: string;

  @ApiPropertyOptional({ description: 'Finding description' })
  @IsOptional()
  @IsString()
  description?: string;

  @ApiPropertyOptional({ description: 'Severity level', enum: FindingSeverity })
  @IsOptional()
  @IsEnum(FindingSeverity)
  severity?: FindingSeverity;

  @ApiPropertyOptional({ description: 'Status', enum: FindingStatus })
  @IsOptional()
  @IsEnum(FindingStatus)
  status?: FindingStatus;

  @ApiPropertyOptional({ description: 'Due date (YYYY-MM-DD)' })
  @IsOptional()
  @IsDateString()
  dueDate?: string;

  @ApiPropertyOptional({ description: 'Assignee ID' })
  @IsOptional()
  @IsString()
  assigneeId?: string;

  @ApiPropertyOptional({ description: 'Corrective action description' })
  @IsOptional()
  @IsString()
  correctiveAction?: string;

  @ApiPropertyOptional({ description: 'Root cause analysis' })
  @IsOptional()
  @IsString()
  rootCause?: string;
}

export class ResolveFindingDto {
  @ApiProperty({ description: 'Resolution notes' })
  @IsString()
  resolutionNotes: string;

  @ApiPropertyOptional({ description: 'Corrective action taken' })
  @IsOptional()
  @IsString()
  correctiveAction?: string;

  @ApiPropertyOptional({ description: 'Root cause identified' })
  @IsOptional()
  @IsString()
  rootCause?: string;

  @ApiPropertyOptional({ description: 'Verification required', default: false })
  @IsOptional()
  @IsBoolean()
  requiresVerification?: boolean;
}

export class GetTrendsDto {
  @ApiPropertyOptional({ description: 'Period: week, month, quarter, year', default: 'month' })
  @IsOptional()
  @IsString()
  period?: 'week' | 'month' | 'quarter' | 'year';

  @ApiPropertyOptional({ description: 'Start date (YYYY-MM-DD)' })
  @IsOptional()
  @IsDateString()
  startDate?: string;

  @ApiPropertyOptional({ description: 'End date (YYYY-MM-DD)' })
  @IsOptional()
  @IsDateString()
  endDate?: string;

  @ApiPropertyOptional({ description: 'Filter by department' })
  @IsOptional()
  @IsString()
  department?: string;

  @ApiPropertyOptional({ description: 'Filter by audit type', enum: AuditType })
  @IsOptional()
  @IsEnum(AuditType)
  auditType?: AuditType;
}

// ============ Response DTOs ============

export class AuditorResponseDto {
  @ApiProperty()
  id: string;

  @ApiProperty()
  name: string;

  @ApiPropertyOptional()
  email?: string;

  @ApiPropertyOptional()
  department?: string;
}

export class AuditResponseDto {
  @ApiProperty()
  id: string;

  @ApiProperty()
  title: string;

  @ApiProperty({ enum: AuditType })
  type: AuditType;

  @ApiProperty({ enum: AuditStatus })
  status: AuditStatus;

  @ApiProperty()
  scheduledDate: string;

  @ApiPropertyOptional()
  completedDate?: string;

  @ApiProperty({ type: AuditorResponseDto })
  auditor: AuditorResponseDto;

  @ApiPropertyOptional()
  department?: string;

  @ApiPropertyOptional()
  location?: string;

  @ApiPropertyOptional()
  score?: number;

  @ApiPropertyOptional()
  maxScore?: number;

  @ApiProperty()
  findingsCount: number;

  @ApiProperty()
  createdAt: string;

  @ApiProperty()
  updatedAt: string;
}

export class AuditDetailResponseDto extends AuditResponseDto {
  @ApiPropertyOptional()
  checklist?: GembaChecklist;

  @ApiProperty({ type: [Object] })
  findings: GembaFinding[];

  @ApiPropertyOptional()
  notes?: string;
}

export class FindingResponseDto {
  @ApiProperty()
  id: string;

  @ApiProperty()
  auditId: string;

  @ApiProperty()
  title: string;

  @ApiProperty()
  description: string;

  @ApiProperty({ enum: FindingSeverity })
  severity: FindingSeverity;

  @ApiProperty({ enum: FindingStatus })
  status: FindingStatus;

  @ApiPropertyOptional()
  dueDate?: string;

  @ApiPropertyOptional({ type: AuditorResponseDto })
  assignee?: AuditorResponseDto;

  @ApiProperty({ type: [String] })
  photos: string[];

  @ApiPropertyOptional()
  correctiveAction?: string;

  @ApiPropertyOptional()
  rootCause?: string;

  @ApiProperty()
  createdAt: string;

  @ApiProperty()
  updatedAt: string;

  @ApiPropertyOptional()
  resolvedAt?: string;

  @ApiProperty()
  isOverdue: boolean;
}

export class ChecklistResponseDto {
  @ApiProperty()
  id: string;

  @ApiProperty()
  name: string;

  @ApiProperty()
  version: string;

  @ApiPropertyOptional()
  description?: string;

  @ApiProperty()
  totalItems: number;

  @ApiProperty()
  categoryCount: number;

  @ApiProperty()
  createdAt: string;

  @ApiProperty()
  updatedAt: string;
}

export class ChecklistDetailResponseDto extends ChecklistResponseDto {
  @ApiProperty({ type: [Object] })
  categories: GembaChecklistCategory[];
}

export class StatisticsResponseDto {
  @ApiProperty()
  totalAudits: number;

  @ApiProperty()
  completedAudits: number;

  @ApiProperty()
  scheduledAudits: number;

  @ApiProperty()
  overdueAudits: number;

  @ApiProperty()
  totalFindings: number;

  @ApiProperty()
  openFindings: number;

  @ApiProperty()
  resolvedFindings: number;

  @ApiProperty()
  averageComplianceScore: number;

  @ApiProperty()
  complianceScoreChange: number;

  @ApiProperty({ type: 'object' })
  auditsByType: Record<string, number>;

  @ApiProperty({ type: 'object' })
  findingsBySeverity: Record<string, number>;

  @ApiProperty({ type: 'object' })
  findingsByStatus: Record<string, number>;
}

export class TrendResponseDto {
  @ApiProperty()
  period: string;

  @ApiProperty()
  startDate: string;

  @ApiProperty()
  endDate: string;

  @ApiProperty({ type: [Object] })
  dataPoints: GembaTrendDataPoint[];
}

export class PaginatedAuditsResponseDto {
  @ApiProperty({ type: [AuditResponseDto] })
  audits: AuditResponseDto[];

  @ApiProperty()
  total: number;

  @ApiProperty()
  page: number;

  @ApiProperty()
  pageSize: number;

  @ApiProperty()
  totalPages: number;
}

export class PaginatedFindingsResponseDto {
  @ApiProperty({ type: [FindingResponseDto] })
  findings: FindingResponseDto[];

  @ApiProperty()
  total: number;

  @ApiProperty()
  page: number;

  @ApiProperty()
  pageSize: number;

  @ApiProperty()
  totalPages: number;
}
