import { ApiPropertyOptional } from '@nestjs/swagger';
import { plainToInstance, Transform, Type } from 'class-transformer';
import {
  Allow,
  ArrayMinSize,
  IsArray,
  IsIn,
  IsInt,
  IsOptional,
  Max,
  Min,
  ValidateNested,
} from 'class-validator';

import {
  toIssueEscalationTarget,
  toIssueResolveStatus,
  toNumberArray,
} from './meeting-summary-transformers';

// The status tokens stored on IssueResolves (must match the Prisma enum
// IssueResolveStatus). The "New Submission" UI label means "no resolve yet".
export const ISSUE_RESOLVE_STATUSES = [
  'SOLVED',
  'IN_PROGRESS',
  'NOT_ADDRESSED',
] as const;

// The escalation targets a ministry can pick in the update-issue dialog.
export const ISSUE_ESCALATION_NAMES = ['CDC', 'CEFP'] as const;

export class IssueGovernmentAgencyInputDto {
  @Type(() => Number)
  @IsInt()
  @Min(1)
  stakeholderId!: number;

  @Type(() => Number)
  @IsInt()
  @Min(1)
  @Max(5)
  agencyOrder!: number;
}

function parseGovernmentAgencies(value: unknown) {
  if (typeof value !== 'string') {
    return value;
  }

  try {
    const parsed: unknown = JSON.parse(value);

    return Array.isArray(parsed)
      ? plainToInstance(IssueGovernmentAgencyInputDto, parsed)
      : parsed;
  } catch {
    return value;
  }
}

/**
 * One issue's resolution inside a meeting summary. Each entry maps to a row in
 * the issue_resolves table for a single issue of the linked meeting request.
 */
export class IssueResolveInputDto {
  @ApiPropertyOptional({
    example: 5,
    description: 'ID of the meeting-request issue being resolved.',
  })
  @Type(() => Number)
  @IsInt()
  @Min(1)
  issueId!: number;

  @ApiPropertyOptional({
    enum: ISSUE_RESOLVE_STATUSES,
    description: 'Resolution status. Accepts UI labels like "In Progress".',
  })
  @IsOptional()
  @Transform(({ value }) => toIssueResolveStatus(value))
  @IsIn(ISSUE_RESOLVE_STATUSES)
  status?: string;

  @ApiPropertyOptional({
    enum: ISSUE_ESCALATION_NAMES,
    nullable: true,
    description: 'Escalation target. Resolved to an escalate row by name.',
  })
  @IsOptional()
  @Transform(({ value }) => toIssueEscalationTarget(value))
  @IsIn(ISSUE_ESCALATION_NAMES)
  escalate?: string | null;

  @ApiPropertyOptional({
    description: 'RGC decision (rich-text editor value).',
  })
  @IsOptional()
  @Allow()
  rgcDecision?: unknown;

  @ApiPropertyOptional({ description: 'Next step (rich-text editor value).' })
  @IsOptional()
  @Allow()
  nextStep?: unknown;

  @ApiPropertyOptional({ description: 'Remark (rich-text editor value).' })
  @IsOptional()
  @Allow()
  remark?: unknown;

  @ApiPropertyOptional({
    type: [Number],
    example: [2, 3],
    description: 'Stakeholder IDs for the extra (2nd–5th) agencies.',
  })
  @IsOptional()
  @Transform(({ value }) => toNumberArray(value))
  @IsArray()
  @IsInt({ each: true })
  @Min(1, { each: true })
  agencyStakeholderIds?: number[];

  @ApiPropertyOptional({
    type: [IssueGovernmentAgencyInputDto],
    description:
      'The complete ordered government-agency list to update on the original issue.',
  })
  @IsOptional()
  @Transform(({ value }) => parseGovernmentAgencies(value))
  @IsArray()
  @ArrayMinSize(1)
  @ValidateNested({ each: true })
  @Type(() => IssueGovernmentAgencyInputDto)
  governmentAgencies?: IssueGovernmentAgencyInputDto[];
}
