import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import {
  AssessmentType,
  AssignmentStatus,
  CampaignAutoAssignMode,
  CampaignStatus,
  CronJobExecutionStatus,
  DeliveryStatus,
  QuestionFieldType,
  RecurrenceFrequency,
  ReminderChannel,
  SubmissionFinalStatus,
  UserStatus,
} from '@prisma/client';
import { AuthTokensDto } from '../../modules/auth/dto/auth-tokens.dto';
import { AuthUserDto } from '../../modules/auth/dto/auth-user.dto';

export class HealthResponseDto {
  @ApiProperty({ example: 'ok' })
  status!: string;

  @ApiProperty({ example: 'api' })
  service!: string;
}

export class BooleanSuccessDto {
  @ApiProperty({ example: true })
  success!: boolean;
}

export class PermissionResponseDto {
  @ApiProperty()
  id!: string;

  @ApiProperty()
  key!: string;

  @ApiProperty()
  label!: string;

  @ApiProperty()
  module!: string;

  @ApiProperty()
  createdAt!: Date;

  @ApiProperty()
  updatedAt!: Date;

  @ApiPropertyOptional({ nullable: true })
  deletedAt?: Date | null;
}

export class RolePermissionResponseDto {
  @ApiProperty()
  id!: string;

  @ApiProperty()
  roleId!: string;

  @ApiProperty()
  permissionId!: string;

  @ApiProperty({ type: () => PermissionResponseDto })
  permission!: PermissionResponseDto;
}

export class RoleResponseDto {
  @ApiProperty()
  id!: string;

  @ApiProperty()
  name!: string;

  @ApiProperty()
  slug!: string;

  @ApiPropertyOptional()
  description?: string | null;

  @ApiProperty()
  createdAt!: Date;

  @ApiProperty()
  updatedAt!: Date;

  @ApiPropertyOptional({ nullable: true })
  deletedAt?: Date | null;
}

export class RoleDetailResponseDto extends RoleResponseDto {
  @ApiProperty({ type: () => [RolePermissionResponseDto] })
  rolePermissions!: RolePermissionResponseDto[];
}

export class DepartmentResponseDto {
  @ApiProperty()
  id!: string;

  @ApiProperty()
  name!: string;

  @ApiProperty()
  code!: string;

  @ApiPropertyOptional()
  description?: string | null;

  @ApiProperty()
  createdAt!: Date;

  @ApiProperty()
  updatedAt!: Date;

  @ApiPropertyOptional({ nullable: true })
  deletedAt?: Date | null;
}

export class UserSummaryResponseDto {
  @ApiProperty()
  id!: string;

  @ApiProperty()
  employeeCode!: string;

  @ApiProperty()
  name!: string;

  @ApiProperty()
  email!: string;

  @ApiProperty()
  designation!: string;

  @ApiProperty({ enum: UserStatus })
  status!: UserStatus;
}

export class UserResponseDto extends UserSummaryResponseDto {
  @ApiProperty()
  roleId!: string;

  @ApiProperty()
  departmentId!: string;

  @ApiPropertyOptional({ nullable: true })
  managerId?: string | null;

  @ApiPropertyOptional({ type: () => RoleResponseDto })
  role?: RoleResponseDto;

  @ApiPropertyOptional({ type: () => DepartmentResponseDto })
  department?: DepartmentResponseDto;

  @ApiPropertyOptional({ type: () => UserSummaryResponseDto, nullable: true })
  manager?: UserSummaryResponseDto | null;

  @ApiPropertyOptional({ nullable: true })
  lastLoginAt?: Date | null;

  @ApiProperty()
  createdAt!: Date;

  @ApiProperty()
  updatedAt!: Date;

  @ApiPropertyOptional({ nullable: true })
  deletedAt?: Date | null;
}

export class QuestionResponseDto {
  @ApiProperty()
  id!: string;

  @ApiProperty()
  code!: string;

  @ApiProperty()
  label!: string;

  @ApiPropertyOptional()
  description?: string | null;

  @ApiPropertyOptional()
  helpText?: string | null;

  @ApiProperty({ enum: QuestionFieldType })
  fieldType!: QuestionFieldType;

  @ApiPropertyOptional()
  placeholder?: string | null;

  @ApiProperty()
  isRequired!: boolean;

  @ApiPropertyOptional({ type: [String], nullable: true })
  optionsJson?: string[] | null;

  @ApiPropertyOptional({ type: 'object', additionalProperties: true, nullable: true })
  validationJson?: Record<string, unknown> | null;

  @ApiProperty()
  isActive!: boolean;

  @ApiProperty()
  createdAt!: Date;

  @ApiProperty()
  updatedAt!: Date;

  @ApiPropertyOptional({ nullable: true })
  deletedAt?: Date | null;
}

export class TemplateQuestionMappingResponseDto {
  @ApiProperty()
  id!: string;

  @ApiProperty()
  templateId!: string;

  @ApiProperty()
  questionId!: string;

  @ApiProperty()
  sortOrder!: number;

  @ApiPropertyOptional()
  sectionName?: string | null;

  @ApiPropertyOptional({ nullable: true })
  isRequiredOverride?: boolean | null;

  @ApiPropertyOptional({ type: 'object', additionalProperties: true, nullable: true })
  configJson?: Record<string, unknown> | null;

  @ApiProperty({ type: () => QuestionResponseDto })
  question!: QuestionResponseDto;
}

export class TemplateResponseDto {
  @ApiProperty()
  id!: string;

  @ApiProperty()
  name!: string;

  @ApiProperty()
  code!: string;

  @ApiProperty({ enum: AssessmentType })
  assessmentType!: AssessmentType;

  @ApiPropertyOptional()
  description?: string | null;

  @ApiProperty()
  version!: number;

  @ApiProperty()
  isActive!: boolean;

  @ApiProperty()
  createdAt!: Date;

  @ApiProperty()
  updatedAt!: Date;

  @ApiPropertyOptional({ nullable: true })
  deletedAt?: Date | null;
}

export class TemplateDetailResponseDto extends TemplateResponseDto {
  @ApiProperty({ type: () => [TemplateQuestionMappingResponseDto] })
  questions!: TemplateQuestionMappingResponseDto[];
}

export class CampaignResponseDto {
  @ApiProperty()
  id!: string;

  @ApiProperty()
  title!: string;

  @ApiProperty({ enum: AssessmentType })
  assessmentType!: AssessmentType;

  @ApiProperty()
  templateId!: string;

  @ApiPropertyOptional({ nullable: true })
  periodMonth?: number | null;

  @ApiPropertyOptional({ nullable: true })
  periodYear?: number | null;

  @ApiProperty()
  startDate!: Date;

  @ApiProperty()
  endDate!: Date;

  @ApiProperty({ enum: CampaignStatus })
  status!: CampaignStatus;

  @ApiProperty()
  isAutoGenerated!: boolean;

  @ApiProperty({ enum: RecurrenceFrequency })
  recurrenceFrequency!: RecurrenceFrequency;

  @ApiProperty()
  recurrenceInterval!: number;

  @ApiProperty({ enum: CampaignAutoAssignMode })
  autoAssignMode!: CampaignAutoAssignMode;

  @ApiPropertyOptional({ type: [String], nullable: true })
  autoAssignEmployeeIds?: string[] | null;

  @ApiPropertyOptional({ nullable: true })
  nextRunAt?: Date | null;

  @ApiPropertyOptional({ nullable: true })
  lastGeneratedAt?: Date | null;

  @ApiPropertyOptional({ nullable: true })
  sourceCampaignId?: string | null;

  @ApiPropertyOptional({ type: () => TemplateResponseDto })
  template?: TemplateResponseDto;

  @ApiProperty()
  createdAt!: Date;

  @ApiProperty()
  updatedAt!: Date;

  @ApiPropertyOptional({ nullable: true })
  deletedAt?: Date | null;
}

export class SubmissionAnswerResponseDto {
  @ApiProperty()
  id!: string;

  @ApiProperty()
  questionId!: string;

  @ApiPropertyOptional()
  answerText?: string | null;

  @ApiPropertyOptional({ type: 'object', additionalProperties: true, nullable: true })
  answerJson?: unknown;

  @ApiPropertyOptional({ type: () => QuestionResponseDto })
  question?: QuestionResponseDto;
}

export class SubmissionResponseDto {
  @ApiProperty()
  id!: string;

  @ApiProperty()
  assignmentId!: string;

  @ApiPropertyOptional({ nullable: true })
  submittedBy?: string | null;

  @ApiPropertyOptional({ nullable: true })
  submittedAt?: Date | null;

  @ApiProperty({ enum: SubmissionFinalStatus })
  finalStatus!: SubmissionFinalStatus;

  @ApiPropertyOptional({ type: () => [SubmissionAnswerResponseDto] })
  answers?: SubmissionAnswerResponseDto[];
}

export class AssignmentResponseDto {
  @ApiProperty()
  id!: string;

  @ApiProperty()
  campaignId!: string;

  @ApiProperty()
  employeeId!: string;

  @ApiPropertyOptional({ nullable: true })
  assignedBy?: string | null;

  @ApiProperty()
  assignedAt!: Date;

  @ApiProperty()
  isEnabled!: boolean;

  @ApiPropertyOptional({ nullable: true })
  enabledBy?: string | null;

  @ApiPropertyOptional({ nullable: true })
  enabledAt?: Date | null;

  @ApiPropertyOptional({ nullable: true })
  reopenUntil?: Date | null;

  @ApiProperty({ enum: AssignmentStatus })
  status!: AssignmentStatus;

  @ApiPropertyOptional({ type: () => CampaignResponseDto })
  campaign?: CampaignResponseDto;

  @ApiPropertyOptional({ type: () => UserSummaryResponseDto })
  employee?: UserSummaryResponseDto;

  @ApiPropertyOptional({ type: () => [SubmissionResponseDto] })
  submissions?: SubmissionResponseDto[];

  @ApiProperty()
  createdAt!: Date;

  @ApiProperty()
  updatedAt!: Date;

  @ApiPropertyOptional({ nullable: true })
  deletedAt?: Date | null;
}

export class CampaignDetailResponseDto extends CampaignResponseDto {
  @ApiProperty({ type: () => TemplateDetailResponseDto })
  declare template: TemplateDetailResponseDto;

  @ApiProperty({ type: () => [AssignmentResponseDto] })
  assignments!: AssignmentResponseDto[];
}

export class AssignmentDetailResponseDto extends AssignmentResponseDto {
  @ApiProperty({ type: () => CampaignDetailResponseDto })
  declare campaign: CampaignDetailResponseDto;

  @ApiProperty({ type: () => UserSummaryResponseDto })
  declare employee: UserSummaryResponseDto;

  @ApiProperty({ type: () => [SubmissionResponseDto] })
  declare submissions: SubmissionResponseDto[];
}

export class AssignmentFormQuestionResponseDto {
  @ApiProperty()
  mappingId!: string;

  @ApiProperty()
  sortOrder!: number;

  @ApiPropertyOptional()
  sectionName?: string | null;

  @ApiProperty()
  isRequired!: boolean;

  @ApiPropertyOptional({ type: 'object', additionalProperties: true, nullable: true })
  configJson?: Record<string, unknown> | null;

  @ApiProperty({ type: () => QuestionResponseDto })
  question!: QuestionResponseDto;
}

export class AssignmentFormEmployeeContextResponseDto {
  @ApiProperty()
  designation!: string;

  @ApiProperty()
  reportingManager!: string;

  @ApiProperty()
  reportMonth!: string;
}

export class AssignmentFormResponseDto {
  @ApiProperty({
    type: 'object',
    properties: {
      id: { type: 'string' },
      status: { enum: AssignmentStatus },
      isEnabled: { type: 'boolean' },
      reopenUntil: { type: 'string', format: 'date-time', nullable: true },
    },
  })
  assignment!: {
    id: string;
    status: AssignmentStatus;
    isEnabled: boolean;
    reopenUntil: Date | null;
  };

  @ApiProperty({ type: () => CampaignResponseDto })
  campaign!: CampaignResponseDto;

  @ApiProperty({ type: () => TemplateDetailResponseDto })
  template!: TemplateDetailResponseDto;

  @ApiProperty({ type: () => AssignmentFormEmployeeContextResponseDto })
  employeeContext!: AssignmentFormEmployeeContextResponseDto;

  @ApiProperty({ type: () => [AssignmentFormQuestionResponseDto] })
  questions!: AssignmentFormQuestionResponseDto[];

  @ApiPropertyOptional({ type: () => SubmissionResponseDto, nullable: true })
  submission?: SubmissionResponseDto | null;
}

export class ReminderLogResponseDto {
  @ApiProperty()
  id!: string;

  @ApiProperty()
  assignmentId!: string;

  @ApiProperty({ enum: ReminderChannel })
  channel!: ReminderChannel;

  @ApiProperty()
  recipient!: string;

  @ApiProperty()
  subject!: string;

  @ApiProperty()
  body!: string;

  @ApiProperty()
  sentAt!: Date;

  @ApiProperty({ enum: DeliveryStatus })
  deliveryStatus!: DeliveryStatus;

  @ApiPropertyOptional({ type: 'object', additionalProperties: true, nullable: true })
  metaJson?: Record<string, unknown> | null;

  @ApiPropertyOptional({ type: () => AssignmentResponseDto })
  assignment?: AssignmentResponseDto;
}

export class ReminderRunSummaryResponseDto {
  @ApiProperty()
  processed!: number;

  @ApiProperty()
  sent!: number;

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

export class CronJobRunResponseDto {
  @ApiProperty()
  skipped!: boolean;

  @ApiProperty()
  logId!: string;

  @ApiPropertyOptional()
  reason?: string;

  @ApiPropertyOptional()
  campaignId?: string;

  @ApiPropertyOptional()
  processed?: number;

  @ApiPropertyOptional()
  sent?: number;

  @ApiPropertyOptional({ type: [String] })
  reminderLogIds?: string[];

  @ApiPropertyOptional()
  lockedCount?: number;
}

export class CampaignSummaryReportItemDto {
  @ApiProperty()
  id!: string;

  @ApiProperty()
  title!: string;

  @ApiProperty({ enum: AssessmentType })
  assessmentType!: AssessmentType;

  @ApiPropertyOptional({ nullable: true })
  periodMonth?: number | null;

  @ApiPropertyOptional({ nullable: true })
  periodYear?: number | null;

  @ApiProperty({ enum: CampaignStatus })
  status!: CampaignStatus;

  @ApiProperty()
  templateName!: string;

  @ApiProperty()
  totalAssignments!: number;

  @ApiProperty()
  submitted!: number;

  @ApiProperty()
  pending!: number;

  @ApiProperty()
  locked!: number;

  @ApiProperty()
  missed!: number;

  @ApiProperty()
  submissionRate!: number;
}

export class CampaignSummaryReportResponseDto {
  @ApiProperty()
  totalCampaigns!: number;

  @ApiProperty()
  totalAssignments!: number;

  @ApiProperty()
  submitted!: number;

  @ApiProperty()
  pending!: number;

  @ApiProperty()
  locked!: number;

  @ApiProperty()
  missed!: number;

  @ApiProperty({ type: () => [CampaignSummaryReportItemDto] })
  campaigns!: CampaignSummaryReportItemDto[];
}

export class ExportRowDto {
  @ApiProperty()
  title!: string;

  @ApiProperty({ enum: AssessmentType })
  assessmentType!: AssessmentType;

  @ApiPropertyOptional({ nullable: true })
  periodMonth?: number | null;

  @ApiPropertyOptional({ nullable: true })
  periodYear?: number | null;

  @ApiProperty({ enum: CampaignStatus })
  status!: CampaignStatus;

  @ApiProperty()
  templateName!: string;

  @ApiProperty()
  totalAssignments!: number;

  @ApiProperty()
  submitted!: number;

  @ApiProperty()
  pending!: number;

  @ApiProperty()
  locked!: number;

  @ApiProperty()
  missed!: number;

  @ApiProperty()
  submissionRate!: number;
}

export class ExportPayloadResponseDto {
  @ApiProperty({ type: [String] })
  headers!: string[];

  @ApiProperty({ type: () => [ExportRowDto] })
  rows!: ExportRowDto[];
}

export class EmployeeHistoryResponseDto {
  @ApiProperty({ type: () => UserResponseDto })
  employee!: UserResponseDto;

  @ApiProperty({ type: () => [AssignmentDetailResponseDto] })
  history!: AssignmentDetailResponseDto[];
}

export class CronJobLogResponseDto {
  @ApiProperty()
  id!: string;

  @ApiProperty()
  jobName!: string;

  @ApiProperty()
  startedAt!: Date;

  @ApiPropertyOptional({ nullable: true })
  endedAt?: Date | null;

  @ApiProperty({ enum: CronJobExecutionStatus })
  status!: CronJobExecutionStatus;
}

export class LoginResponseDto extends AuthTokensDto {}

export class ProfileResponseDto extends AuthUserDto {}
