import { Transform, Type } from 'class-transformer';
import {
  IsBoolean,
  IsEnum,
  IsInt,
  IsOptional,
  IsString,
  Min,
} from 'class-validator';

export enum OutlookBindingActionDto {
  MANAGE = 'MANAGE',
  UNMANAGE = 'UNMANAGE',
}

const toBoolean = ({ value }: { value: unknown }): boolean | undefined => {
  if (value === undefined || value === null || value === '') {
    return undefined;
  }
  if (typeof value === 'boolean') {
    return value;
  }
  if (typeof value === 'number') {
    return value !== 0;
  }
  const normalized = String(value).trim().toLowerCase();
  if (['true', '1', 'yes', 'y', 'on'].includes(normalized)) {
    return true;
  }
  if (['false', '0', 'no', 'n', 'off'].includes(normalized)) {
    return false;
  }
  return undefined;
};

export class ListOutlookCandidatesQueryDto {
  @IsOptional()
  @IsString()
  mailboxId?: string;

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

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

  @IsOptional()
  @IsBoolean()
  @Transform(toBoolean)
  includeCancelled?: boolean;

  @IsOptional()
  @IsBoolean()
  @Transform(toBoolean)
  includePast?: boolean;

  @IsOptional()
  @IsBoolean()
  @Transform(toBoolean)
  onlyUnmanaged?: boolean;

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

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

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

  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  pageSize?: number;
}

export class ListOutlookCandidateChildrenQueryDto {
  @IsOptional()
  @IsString()
  mailboxId?: string;

  @IsOptional()
  @IsBoolean()
  @Transform(toBoolean)
  includeCancelled?: boolean;

  @IsOptional()
  @IsBoolean()
  @Transform(toBoolean)
  includePast?: boolean;
}

export class ListManagedSeriesChildrenQueryDto {
  @IsOptional()
  @IsString()
  mailboxId?: string;
}

export class ManageOutlookBindingDto {
  @IsString()
  mailboxId!: string;

  @IsString()
  graphEventId!: string;

  @IsString()
  iCalUId!: string;

  @IsEnum(OutlookBindingActionDto)
  action!: OutlookBindingActionDto;
}

export class ListManagedOutlookBindingsQueryDto {
  @IsString()
  mailboxId!: string;

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

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

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

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

  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  pageSize?: number;
}

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

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

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

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

  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  pageSize?: number;
}

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

  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  pageSize?: number;

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

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

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

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

  @IsOptional()
  @IsBoolean()
  @Transform(toBoolean)
  onlyError?: boolean;
}

export class TakeoverOutlookBindingDto {
  @IsOptional()
  @IsString()
  mailboxId?: string;
}

export class ExcludeOutlookSeriesOccurrenceDto {
  @IsString()
  occurrenceGraphEventId!: string;

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

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

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

  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  pageSize?: number;
}

export class UpdateOutlookSyncSettingsDto {
  @IsOptional()
  @IsString()
  reconcileCron?: string;

  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  deltaBatchSize?: number;

  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  lookaheadDays?: number;

  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(0)
  lookbackDays?: number;

  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(10)
  renewBeforeMinutes?: number;

  @IsOptional()
  @IsBoolean()
  @Transform(toBoolean)
  includeOrganizerAsAttendee?: boolean;
}
