import {
  ApiExtraModels,
  ApiProperty,
  ApiPropertyOptional,
  IntersectionType,
  OmitType,
  PartialType,
  PickType,
} from '@nestjs/swagger';
import { Expose, Transform, Type } from 'class-transformer';
import {
  IsArray,
  IsEnum,
  IsInt,
  IsObject,
  IsOptional,
  IsString,
  ValidateNested,
} from 'class-validator';
import { Agency } from '../agency/agency/agency.entity';
import {
  CountDto,
  DateSearchDto,
  IdsDto,
  PaginationDto,
  SearchDto,
} from '../common/common.dto';
import { Advertisement } from './advertisement.entity';
import { typeParser } from '@lib/utils/type-parser';
import { Member } from '../fc/fc.entity';
import { Alimtalk } from '../alimtalk/alimtalk.entity';

export class AdvertisementImageDto extends PickType(Advertisement, [
  'adsImg',
]) {}

export class CreateAdvertisementDto extends OmitType(Advertisement, [
  'adsId',
  'adsImg',
  'adsCreatedAt',
  'adsUpdatedAt',
  'adsTotalClickCount',
  'adsTotalImpressionCount',
  'adsTotalPlayCount',
]) {}

export class UpdateAdvertisementDto extends OmitType(Advertisement, [
  'adsId',
  'adsCreatedAt',
  'adsUpdatedAt',
  'adsTotalClickCount',
  'adsTotalImpressionCount',
  'adsTotalPlayCount',
]) {}

export class IncreseAdvertisementDto extends PickType(Advertisement, [
  'adsId',
]) {
  @Expose()
  @ApiProperty({
    description: '카운트 증가 타입(click: 클릭 | play: 재생)',
    enum: ['show', 'click', 'play'],
  })
  @IsEnum(['show', 'click', 'play'])
  countType!: 'show' | 'click' | 'play';
}

export class AdvertisementDto extends OmitType(Advertisement, [
  'adsLinked',
  'adsShow',
  'adsLocation',
  'adsRandom',
]) {
  @Expose()
  @ApiProperty({
    description: '광고위치타입',
    enum: [
      '메인하단',
      '진료정보분석하단',
      '청구서하단',
      '고객초대모달',
      '진료정보모달',
    ],
  })
  adsLocation!:
    | '메인하단'
    | '진료정보분석하단'
    | '청구서하단'
    | '고객초대모달'
    | '진료정보모달';

  @Expose()
  @ApiProperty({ description: '노출여부', enum: ['노출', '비노출'] })
  @IsEnum(['노출', '비노출'])
  adsShow!: '노출' | '비노출';

  @Expose()
  @ApiProperty({ description: '링크여부', enum: ['연결', '미연결'] })
  @IsEnum(['연결', '미연결'])
  adsLinked!: '연결' | '미연결';

  @Expose()
  @ApiProperty({ description: '랜덤여부', enum: ['고정', '랜덤'] })
  @IsEnum(['고정', '랜덤'])
  adsRandom!: '고정' | '랜덤';
}

export class AgencyDto extends PickType(Agency, [
  'agcId',
  'agcCorporateName',
]) {}

@ApiExtraModels(IdsDto)
export class DeleteAdvertisementDto extends IntersectionType(IdsDto) {}

export class GetAdvertisementStatisDto {
  @Expose()
  @ApiProperty({
    description: '통계 타입(month: 월별, day: 일별)',
    enum: ['month', 'day'],
  })
  @IsEnum(['month', 'day'])
  dateType!: 'month' | 'day';

  @Expose()
  @ApiProperty({
    description: '조회연도',
    example: '2025',
  })
  @IsString()
  year!: string;

  @Expose()
  @ApiPropertyOptional({
    description: '조회월(dateType이 day(일별)인 경우 포함)',
    example: '05',
  })
  @IsString()
  @IsOptional()
  month?: string;
}

export class GetCommonAdvertisementListDto extends IntersectionType(
  PaginationDto,
  DateSearchDto,
  SearchDto,
  PartialType(
    PickType(Advertisement, [
      'adsShow',
      'adsLinked',
      'adsLocation',
      'adsType',
      'agcId',
      'adsRandom',
    ]),
  ),
) {
  @ApiPropertyOptional({
    description: '검색날짜 타입(default: adsCreatedAt)',
    enum: ['adsCreatedAt', 'adsOpenedAt'],
  })
  dateType = 'adsCreatedAt';

  @ApiPropertyOptional({
    description: '검색조건 (default: adsName(광고명)',
    enum: ['adsName'],
  })
  searchKey = 'adsName';

  @ApiPropertyOptional({
    enum: ['adsName', 'adsCreatedAt'],
  })
  sortKey = 'adsCreatedAt';
}

export class GetAdminAdvertisementListDto extends OmitType(
  GetCommonAdvertisementListDto,
  [],
) {}

export class GetUserAdvertisementListDto extends IntersectionType(
  PickType(Advertisement, ['adsLocation']),
  PartialType(PickType(Member, ['memId'])),
  PartialType(PickType(Alimtalk, ['altCode'])),
) {
  @Expose()
  @ApiProperty({ description: '광고 노출 갯수' })
  @Transform(({ value }) => typeParser.int(value))
  @IsInt()
  limit!: number;
}

@ApiExtraModels(AdvertisementDto, AgencyDto)
export class GetAdvertisementDto {
  @Expose()
  @ApiProperty({ type: AdvertisementDto, description: '광고정보' })
  @ValidateNested({ each: true })
  @Type(() => AdvertisementDto)
  @IsObject()
  advertisement!: AdvertisementDto;

  @Expose()
  @ApiPropertyOptional({ type: AgencyDto, description: '기업정보' })
  @ValidateNested({ each: true })
  @Type(() => AgencyDto)
  @IsObject()
  @IsOptional()
  agency?: AgencyDto;
}

@ApiExtraModels(CountDto, GetAdvertisementDto)
export class GetAdvertisementListResponseDto extends IntersectionType(
  CountDto,
) {
  @Expose()
  @ApiPropertyOptional({ type: [GetAdvertisementDto], description: '목록' })
  @ValidateNested({ each: true })
  @Type(() => GetAdvertisementDto)
  @IsArray()
  @IsOptional()
  list?: GetAdvertisementDto[];
}

class GetAdvertisementStaticsCommonDto {
  @Expose()
  @IsInt()
  @ApiProperty({ description: '노출수' })
  totalImpressions!: number;

  @Expose()
  @IsInt()
  @ApiProperty({ description: '전월/전일 대비 노출수 비율' })
  impressionsRate!: number;

  @Expose()
  @IsInt()
  @ApiProperty({ description: '클릭수' })
  totalClicks!: number;

  @Expose()
  @IsInt()
  @ApiProperty({ description: '전월/전일 대비 클릭수 비율' })
  clicksRate!: number;

  @Expose()
  @IsInt()
  @ApiProperty({ description: '재생수' })
  totalPlays!: number;

  @Expose()
  @IsInt()
  @ApiProperty({ description: '전월/전일 대비 재생수 비율' })
  playsRate!: number;
}

class GetAdvertisementStaticsDto extends GetAdvertisementStaticsCommonDto {
  @Expose({ name: 'date' })
  @IsString()
  @ApiProperty({ description: '연월/연월일' })
  date!: string;
}

@ApiExtraModels(GetAdvertisementStaticsDto)
export class GetAdvertisementStaticsResponseDto {
  @Expose()
  @ApiPropertyOptional({
    type: [GetAdvertisementStaticsDto],
    description: '광고통계 상세',
  })
  @Type(() => GetAdvertisementStaticsDto)
  @IsArray()
  @IsOptional()
  statisticsList?: GetAdvertisementStaticsDto[];
}

class GetUserAdvertisementDto extends PickType(Advertisement, [
  'adsId',
  'adsName',
  'adsLocation',
  'adsType',
  'adsVideoUrl',
  'adsImg',
  'adsLink',
  'adsPlaybackType',
  'adsPlaybackTime',
]) {
  @Expose()
  @ApiPropertyOptional({
    description: '광고링크여부',
  })
  @IsString()
  @IsOptional()
  adsLinked?: string;
}

@ApiExtraModels(GetUserAdvertisementDto)
export class GetUserAdvertisementResponseDto {
  @Expose()
  @ApiPropertyOptional({
    type: [GetUserAdvertisementDto],
    description: '유저 광고 리턴',
  })
  @Type(() => GetUserAdvertisementDto)
  @IsArray()
  @IsOptional()
  list?: GetUserAdvertisementDto[];
}
