import { typeParser } from '@lib/utils/type-parser';
import {
  ApiExtraModels,
  ApiProperty,
  ApiPropertyOptional,
  PickType,
} from '@nestjs/swagger';
import { Expose, Transform, Type } from 'class-transformer';
import {
  IsArray,
  IsInt,
  IsObject,
  IsOptional,
  IsString,
  ValidateNested,
} from 'class-validator';
import { Member } from '../fc/fc.entity';

export class GetStatisticsListDto {
  @Expose()
  @ApiPropertyOptional({
    description: '조회연월',
    example: '2025-01 또는 2025-01-dd (default:당월)',
  })
  @IsString()
  @IsOptional()
  yearMonth?: string;
}

export class GetSignUpMonthDto extends PickType(Member, ['memType']) {
  @Expose()
  @ApiPropertyOptional({
    description: '조회연도',
    example: '2025 또는 2025-mm-dd (default:당연도)',
  })
  @IsString()
  @IsOptional()
  year!: string;
}

export class GetSignUpDayDto extends PickType(Member, ['memType']) {
  @Expose()
  @ApiPropertyOptional({
    description: '조회연월',
    example: '2025-01 또는 2025-01-dd (default:당월)',
  })
  @IsString()
  @IsOptional()
  yearMonth!: string;
}

export class GetAnalysisMonthDto {
  @Expose()
  @ApiPropertyOptional({
    description: '조회연도',
    example: '2025 또는 2025-mm-dd (default:당연도)',
  })
  @IsString()
  @IsOptional()
  year!: string;
}

export class GetAnalysisDayDto {
  @Expose()
  @ApiPropertyOptional({
    description: '조회연월',
    example: '2025-01 또는 2025-01-dd (default:당월)',
  })
  @IsString()
  @IsOptional()
  yearMonth!: string;
}

export class GetRevenueMonthDto extends PickType(Member, ['memType']) {
  @Expose()
  @ApiPropertyOptional({
    description: '조회연도',
    example: '2025 또는 2025-mm-dd (default:당연도)',
  })
  @IsString()
  @IsOptional()
  year!: string;
}

export class GetRevenueDayDto extends PickType(Member, ['memType']) {
  @Expose()
  @ApiPropertyOptional({
    description: '조회연월',
    example: '2025-01 또는 2025-01-dd (default:당월)',
  })
  @IsString()
  @IsOptional()
  yearMonth!: string;
}

//--------------------- ResponseDto ---------------------//
class GetPayDailyDto {
  @Expose()
  @ApiProperty({
    description: '날짜',
  })
  @IsString()
  date!: string;

  @Expose()
  @IsInt()
  @ApiProperty({ description: '총 결제(취소)건 수' })
  count!: number;

  @Expose()
  @IsInt()
  @ApiProperty({ description: '총 결제(취소)금액' })
  totalAmount!: number;
}

class GetPayMonthDto {
  @Expose()
  @IsInt()
  @ApiProperty({ description: '총 결제(취소)건 수' })
  count!: number;

  @Expose()
  @IsInt()
  @ApiProperty({ description: '총 결제(취소)금액' })
  totalAmount!: number;
}

class GetAllPayDto {
  @Expose()
  @IsInt()
  @ApiProperty({ description: '총 결제(취소)건 수' })
  count!: number;

  @Expose()
  @IsInt()
  @ApiProperty({ description: '총 결제(취소)금액' })
  totalAmount!: number;
}

@ApiExtraModels(GetPayDailyDto, GetPayMonthDto)
export class GetStatisticsResponseDto {
  @Expose()
  @IsInt()
  @ApiProperty({ description: '전체 회원 수' })
  allMemberQty!: number;

  @Expose()
  @IsInt()
  @ApiProperty({ description: '해당월 신규 회원 수' })
  memberQty!: number;

  @Expose()
  @IsInt()
  @ApiProperty({ description: '해당월 분석완료건 수' })
  usedQty!: number;

  @Expose()
  @IsInt()
  @ApiProperty({ description: '전체 분석완료건 수' })
  allUsedQty!: number;

  @Expose()
  @ApiProperty({ type: GetPayMonthDto, description: '해당월 결제정보' })
  @ValidateNested({ each: true })
  @Type(() => GetPayMonthDto)
  @IsObject()
  payMonth!: GetPayMonthDto;

  @Expose()
  @ApiProperty({ type: GetPayMonthDto, description: '해당월 결제취소정보' })
  @ValidateNested({ each: true })
  @Type(() => GetPayMonthDto)
  @IsObject()
  payCancelMonth!: GetPayMonthDto;

  @Expose()
  @ApiPropertyOptional({
    type: [GetPayDailyDto],
    description: '일별 결제금액 목록',
  })
  @Type(() => GetPayDailyDto)
  @IsArray()
  @IsOptional()
  payList?: GetPayDailyDto[];

  @Expose()
  @ApiPropertyOptional({
    type: [GetPayDailyDto],
    description: '일별 결제취소금액 목록',
  })
  @Type(() => GetPayDailyDto)
  @IsArray()
  @IsOptional()
  payCancelList?: GetPayDailyDto[];

  @Expose()
  @ApiProperty({
    type: [GetAllPayDto],
    description: '전체 결제금액',
  })
  @Type(() => GetAllPayDto)
  @IsObject()
  @IsOptional()
  allPay?: GetAllPayDto;

  @Expose()
  @ApiProperty({
    type: [GetAllPayDto],
    description: '전체 결제금액',
  })
  @Type(() => GetAllPayDto)
  @IsObject()
  @IsOptional()
  allPayCancel?: GetAllPayDto;
}

class GetAnalysisOverallRateDto {
  @Expose()
  @IsInt()
  @ApiProperty({ description: '분석완료 비율' })
  successRate!: number;

  @Expose()
  @IsInt()
  @ApiProperty({ description: '분석실패 비율' })
  failureRate!: number;
}

class GetAnalysisFailureRateDto {
  @Expose()
  @IsInt()
  @ApiProperty({ description: '인증실패 비율' })
  authFailureRate!: number;

  @Expose()
  @IsInt()
  @ApiProperty({ description: '분석실패 비율' })
  analysisFailureRate!: number;

  @Expose()
  @IsInt()
  @ApiProperty({ description: '그 외 비율' })
  etcRate!: number;
}

@ApiExtraModels(GetAnalysisOverallRateDto, GetAnalysisFailureRateDto)
class GetAnalysisRateCommonDto {
  @Expose()
  @ApiProperty({
    type: GetAnalysisOverallRateDto,
    description: '분석완료/분석실패 비율',
  })
  @ValidateNested({ each: true })
  @Type(() => GetAnalysisOverallRateDto)
  @IsObject()
  analysisOverallRate!: GetAnalysisOverallRateDto;

  @Expose()
  @ApiProperty({
    type: GetAnalysisFailureRateDto,
    description: '인증실패/분석실패/기타 비율',
  })
  @ValidateNested({ each: true })
  @Type(() => GetAnalysisFailureRateDto)
  @IsObject()
  analysisFailureRate!: GetAnalysisFailureRateDto;
}

class GetAnalysisStatisticsDetailCommonDto {
  @Expose()
  @IsInt()
  @ApiProperty({ description: '총 건 수' })
  totalCount!: number;

  @Expose()
  @IsInt()
  @ApiProperty({ description: '분석완료 건 수' })
  successCount!: number;

  @Expose()
  @IsInt()
  @ApiProperty({ description: '분석실패 건 수' })
  failureCount!: number;

  @Expose()
  @IsInt()
  @ApiProperty({ description: '분석완료 비율' })
  successRate!: number;

  @Expose()
  @IsInt()
  @ApiProperty({ description: '분석실패 비율' })
  failureRate!: number;
}

class GetAnalysisMonthlyDto extends GetAnalysisStatisticsDetailCommonDto {
  @Expose({ name: 'date' })
  @IsString()
  @ApiProperty({ description: '연월' })
  month!: string;
}

@ApiExtraModels(GetAnalysisRateCommonDto, GetAnalysisMonthlyDto)
export class GetAnalysisMonthlyResponseDto extends GetAnalysisRateCommonDto {
  @Expose()
  @ApiPropertyOptional({
    type: [GetAnalysisMonthlyDto],
    description: '분석결과 상세',
  })
  @Type(() => GetAnalysisMonthlyDto)
  @IsArray()
  @IsOptional()
  statisticsList?: GetAnalysisMonthlyDto[];
}

class GetAnalysisDailyDto extends GetAnalysisStatisticsDetailCommonDto {
  @Expose({ name: 'date' })
  @IsString()
  @ApiProperty({ description: '연월일' })
  day!: string;
}

@ApiExtraModels(GetAnalysisRateCommonDto, GetAnalysisDailyDto)
export class GetAnalysisDailyResponseDto extends GetAnalysisRateCommonDto {
  @Expose()
  @ApiPropertyOptional({
    type: [GetAnalysisDailyDto],
    description: '분석결과 상세',
  })
  @Type(() => GetAnalysisDailyDto)
  @IsArray()
  @IsOptional()
  statisticsList?: GetAnalysisDailyDto[];
}

class GetRevenueStatisticsCommonDto {
  @Expose()
  @IsInt()
  @Transform(({ value }) => typeParser.int(value))
  @ApiProperty({ description: '결제 금액' })
  payAmount!: number;

  @Expose()
  @IsInt()
  @Transform(({ value }) => typeParser.int(value))
  @ApiProperty({ description: '결제취소 금액' })
  cancelAmount!: number;
}

class GetRevenueMonthlyDto extends GetRevenueStatisticsCommonDto {
  @Expose({ name: 'date' })
  @IsString()
  @ApiProperty({ description: '연월' })
  month!: string;
}

@ApiExtraModels(GetRevenueMonthlyDto)
export class GetRevenueMonthlyResponseDto {
  @Expose()
  @ApiPropertyOptional({
    type: [GetRevenueMonthlyDto],
    description: '매출결과 상세',
  })
  @Type(() => GetRevenueMonthlyDto)
  @IsArray()
  @IsOptional()
  statisticsList?: GetRevenueMonthlyDto[];
}

class GetRevenueDailyDto extends GetRevenueStatisticsCommonDto {
  @Expose({ name: 'date' })
  @IsString()
  @ApiProperty({ description: '연월일' })
  day!: string;
}

@ApiExtraModels(GetRevenueDailyDto)
export class GetRevenueDailyResponseDto {
  @Expose()
  @ApiPropertyOptional({
    type: [GetRevenueDailyDto],
    description: '매출결과 상세',
  })
  @Type(() => GetRevenueDailyDto)
  @IsArray()
  @IsOptional()
  statisticsList?: GetRevenueDailyDto[];
}

class GetSignUpStatisticsCommonDto {
  @Expose()
  @IsInt()
  @ApiProperty({ description: '가입자수' })
  signupCount!: number;

  @Expose()
  @IsInt()
  @ApiProperty({ description: '탈퇴자수' })
  resignCount!: number;

  @Expose()
  @IsInt()
  @ApiProperty({ description: '전월/전일 대비(가입자수)' })
  signupRate!: number;

  @Expose()
  @IsInt()
  @ApiProperty({ description: '전월/전일 대비(탈퇴자수)' })
  resignRate!: number;
}

class GetSignUpMonthlyDto extends GetSignUpStatisticsCommonDto {
  @Expose({ name: 'date' })
  @IsString()
  @ApiProperty({ description: '연월' })
  month!: string;
}

@ApiExtraModels(GetSignUpMonthlyDto)
export class GetSignUpMonthlyResponseDto {
  @Expose()
  @ApiPropertyOptional({
    type: [GetSignUpMonthlyDto],
    description: '가입통계 상세',
  })
  @Type(() => GetSignUpMonthlyDto)
  @IsArray()
  @IsOptional()
  statisticsList?: GetSignUpMonthlyDto[];
}

class GetSignUpDailyDto extends GetSignUpStatisticsCommonDto {
  @Expose({ name: 'date' })
  @IsString()
  @ApiProperty({ description: '연월일' })
  day!: string;
}

@ApiExtraModels(GetSignUpDailyDto)
export class GetSignUpDailyResponseDto {
  @Expose()
  @ApiPropertyOptional({
    type: [GetSignUpDailyDto],
    description: '가입통계 상세',
  })
  @Type(() => GetSignUpDailyDto)
  @IsArray()
  @IsOptional()
  statisticsList?: GetSignUpDailyDto[];
}
