import { ApiProperty } from '@nestjs/swagger';
import { Transform, Type } from 'class-transformer';
import {
    ArrayMaxSize, ArrayUnique, IsNotEmpty, IsArray, IsBoolean, IsEmail, IsEnum, IsIn, IsInt, IsMongoId, IsNumber,
    IsOptional, IsString, Matches, Max, MaxLength, Min, MinLength, ValidateNested
} from 'class-validator';
import { AgentDocumentType, AgentStatus } from 'src/user/schema/users.schema';
import { UploadedFileDto } from 'src/common/dto/uploaded-file.dto';

const trim = ({ value }: { value: unknown }) => (typeof value === 'string' ? value.trim() : value);
const lowerTrim = ({ value }: { value: unknown }) => (typeof value === 'string' ? value.trim().toLowerCase() : value);
const upperTrim = ({ value }: { value: unknown }) => (typeof value === 'string' ? value.trim().toUpperCase() : value);

export enum AgentStatusFilter {
    PENDING = 'PENDING' // invited, accepted or submitted: everything not yet approved or rejected
}

export class InviteAgentDto {
    @ApiProperty({ example: 'Rajesh Kumar' })
    @IsString()
    @MinLength(2)
    @MaxLength(80)
    @Transform(trim)
    name: string;

    @ApiProperty({ example: '9876543210', description: 'Mobile number, digits only' })
    @Matches(/^\d{7,15}$/)
    @Transform(trim)
    phone_no: string;

    @ApiProperty({ required: false, default: '+91' })
    @IsOptional()
    @Matches(/^\+\d{1,4}$/)
    @Transform(trim)
    country_code?: string;

    @ApiProperty({ example: 'agent@email.com', description: 'The invitation is sent here (email only)' })
    @IsEmail()
    @Transform(lowerTrim)
    email: string;

    @ApiProperty({ description: 'Region id (must be active). Add regions with POST /admin/regions.' })
    @IsMongoId()
    region_id: string;

    @ApiProperty({ required: false, type: [String], description: 'Category ids the agent may sell' })
    @IsOptional()
    @IsArray()
    @ArrayUnique()
    @IsMongoId({ each: true })
    category_ids?: string[];
}

export class UpdateAgentDto {
    @ApiProperty({ required: false })
    @IsOptional()
    @IsString()
    @MinLength(2)
    @MaxLength(80)
    @Transform(trim)
    name?: string;

    @ApiProperty({ required: false })
    @IsOptional()
    @Matches(/^\d{7,15}$/)
    @Transform(trim)
    phone_no?: string;

    @ApiProperty({ required: false })
    @IsOptional()
    @Matches(/^\+\d{1,4}$/)
    @Transform(trim)
    country_code?: string;

    @ApiProperty({ required: false })
    @IsOptional()
    @IsEmail()
    @Transform(lowerTrim)
    email?: string;

    @ApiProperty({ required: false, description: 'Region id (must be active if changed)' })
    @IsOptional()
    @IsMongoId()
    region_id?: string;

    @ApiProperty({ required: false, type: [String], description: 'Replaces the assigned categories' })
    @IsOptional()
    @IsArray()
    @ArrayUnique()
    @IsMongoId({ each: true })
    category_ids?: string[];

    @ApiProperty({ required: false, description: 'false deactivates the agent' })
    @IsOptional()
    @IsBoolean()
    is_active?: boolean;
}

export class RejectAgentDto {
    @ApiProperty({ example: 'PAN card image is not readable', description: 'Shown to the agent so they can resubmit' })
    @IsString()
    @MinLength(3)
    @MaxLength(300)
    @Transform(trim)
    @IsNotEmpty({ message: 'A rejection note is required' })
    reason: string;
}

export class AgentListDto {
    @ApiProperty({ required: false, default: 1 })
    @IsOptional()
    @Transform(({ value }) => Number(value))
    @IsInt()
    @Min(1)
    page: number = 1;

    @ApiProperty({ required: false, default: 10 })
    @IsOptional()
    @Transform(({ value }) => Number(value))
    @IsInt()
    @Min(1)
    @Max(100)
    limit: number = 10;

    @ApiProperty({ required: false, description: 'Search by name, mobile, email, agent id or region name' })
    @IsOptional()
    @IsString()
    search?: string;

    @ApiProperty({ required: false, enum: [...Object.values(AgentStatus), AgentStatusFilter.PENDING], description: 'PENDING = invited, accepted or submitted' })
    @IsOptional()
    @IsIn([...Object.values(AgentStatus), AgentStatusFilter.PENDING])
    status?: AgentStatus | AgentStatusFilter;

    @ApiProperty({ required: false })
    @IsOptional()
    @IsMongoId()
    region_id?: string;

    @ApiProperty({ required: false, description: 'Only agents assigned this category' })
    @IsOptional()
    @IsMongoId()
    category_id?: string;
}

export class AgentDocumentDto {
    @ApiProperty({ enum: AgentDocumentType })
    @IsEnum(AgentDocumentType)
    type: AgentDocumentType;

    @ApiProperty({ required: false, description: 'Document number: required for PAN (ABCDE1234F); optional for Aadhaar' })
    @IsOptional()
    @IsString()
    @MaxLength(30)
    @Transform(upperTrim)
    number?: string;

    @ApiProperty({ type: UploadedFileDto })
    @ValidateNested()
    @Type(() => UploadedFileDto)
    file: UploadedFileDto;
}

export class SendOtpDto {
    @ApiProperty({ example: '9876543210', description: 'Mobile number the agent was invited on, digits only' })
    @Matches(/^\d{7,15}$/)
    @Transform(trim)
    phone_no: string;

    @ApiProperty({ required: false, default: '+91' })
    @IsOptional()
    @Matches(/^\+\d{1,4}$/)
    @Transform(trim)
    country_code?: string;
}

export class VerifyOtpDto extends SendOtpDto {
    @ApiProperty({ example: '1234', description: 'OTP is mocked as 1234 for now' })
    @IsString()
    @Matches(/^\d{4}$/)
    otp: string;

    @ApiProperty({ required: false, enum: ['IOS', 'ANDROID', 'WEB'] })
    @IsOptional()
    @IsIn(['IOS', 'ANDROID', 'WEB'])
    device_type?: string;

    @ApiProperty({ required: false, description: 'FCM token, used for push notifications' })
    @IsOptional()
    @IsString()
    fcm_token?: string;

    @ApiProperty({ required: false })
    @IsOptional()
    @IsString()
    voip_token?: string;
}

export class SubmitKycDto {
    @ApiProperty({ required: false, description: 'Update your name' })
    @IsOptional()
    @IsString()
    @MinLength(2)
    @MaxLength(80)
    @Transform(trim)
    name?: string;

    @ApiProperty({ required: false, description: 'Needed to receive approval emails' })
    @IsOptional()
    @IsEmail()
    @Transform(lowerTrim)
    email?: string;

    @ApiProperty({ example: 'POSP-IRDAI-2024-9912' })
    @IsString()
    @MinLength(3)
    @MaxLength(50)
    @Transform(upperTrim)
    irdai_number: string;

    @ApiProperty({ example: 15 })
    @IsNumber()
    @Min(0)
    @Max(1000)
    training_hours: number;

    @ApiProperty({ type: [AgentDocumentDto], description: 'One of each: PAN, AADHAAR, ADDRESS_PROOF, LICENSE_CERTIFICATE' })
    @IsArray()
    @ArrayMaxSize(4)
    @ValidateNested({ each: true })
    @Type(() => AgentDocumentDto)
    documents: AgentDocumentDto[];
}
