import { Agency } from '@api/modules/agency/agency/agency.entity';
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,
  ValidateIf,
  ValidateNested,
} from 'class-validator';
import { SignInDto } from '../auth/user/auth.dto';
import {
  CountDto,
  DateSearchDto,
  PaginationDto,
  SearchDto,
} from '../common/common.dto';
import { Order } from '../order/order/order.entity';
import { Subscribe } from '../subscribe/subscribe/subscribe.entity';
import { Member } from './fc.entity';
import { SalesAgency } from '../sales-agency/sales-agency.entity';
import { SalesAgencyChannel } from '../sales-agency/channel/sales-agency-channel.entity';
import { typeParser } from '@lib/utils/type-parser';

export class GetFcListDto extends IntersectionType(
  PaginationDto,
  DateSearchDto,
  SearchDto,
  PartialType(PickType(Member, ['memIsResigned'])),
  PartialType(PickType(Agency, ['agcId'])),
  PartialType(PickType(SalesAgency, ['sagId'])),
  PartialType(PickType(SalesAgencyChannel, ['sacCode'])),
) {
  @ApiPropertyOptional({
    description: '검색날짜 타입 (default: memCreatedAt)',
    enum: ['memCreatedAt', 'memLastLoginAt'],
  })
  dateType = 'memCreatedAt';

  @ApiPropertyOptional({
    description: '검색조건 (default: memName)',
    enum: ['memName', 'memLoginId', 'memPhone', 'memAgency', 'memEmail', 'memReferralCode', 'referrerLoginId'],
  })
  searchKey = 'memName';

  @ApiPropertyOptional({
    enum: [
      'memName',
      'memLoginId',
      'memPhone',
      'memLastLoginAt',
      'memCreatedAt',
    ],
  })
  sortKey = 'memCreatedAt';

  @ApiPropertyOptional({
    description: '추천인입력일자 (전체: "" | 기입: "1" | 미기입: "0")',
    enum: ['', '0', '1'],
  })
  @IsOptional()
  @IsString()
  hasReferralCode?: string;
}

/**
 * toss 인증키 발급을 위한 FC id 암호화
 */
export class EncryptFcDto extends PickType(Member, ['memId']) {}

//--------------------- ResponseDto ---------------------//
class AgencyDto extends PickType(Agency, [
  'agcId',
  'agcCorporateName',
  'agcCorporateCode',
]) {}
class FcDto extends OmitType(Member, ['memPassword', 'memIsResigned']) {
  @Expose()
  @ApiProperty({ description: '탈퇴여부', enum: ['탈퇴', '가입'] })
  @IsEnum(['탈퇴', '가입'])
  memIsResigned!: '탈퇴' | '가입';

  @Expose()
  @ApiPropertyOptional({ description: '추천가입수' })
  @Transform(({ value }) => typeParser.int(value))
  @IsInt()
  @IsOptional()
  referralCount?: number;

  @Expose()
  @ApiPropertyOptional({ description: '추천인ID' })
  @IsOptional()
  referrerLoginId?: string | null;

  //* 기업조직(task-688): 소속 조직명. orgId→tn_agency_organization JOIN으로 파생.
  //* LEFT JOIN 미매칭 시 null 가능 → ValidateIf로 null 통과 허용.
  @Expose()
  @ApiPropertyOptional({ description: '소속 조직명', nullable: true })
  @ValidateIf((_, value) => value !== null && value !== undefined)
  @IsString()
  @IsOptional()
  orgName?: string | null;

  //* 기업조직(task-688): 조직의 ACTIVE 계약에서 파생되는 상품 ID(읽기 전용).
  //* 활성 계약이 없으면 null 가능 → ValidateIf로 null 통과 허용.
  @Expose()
  @ApiPropertyOptional({ description: '상품 ID(조직 ACTIVE 계약 파생)', nullable: true })
  @ValidateIf((_, value) => value !== null && value !== undefined)
  @IsInt()
  @IsOptional()
  prdId?: number | null;

  //* 기업조직(task-688): 조직의 ACTIVE 계약에서 파생되는 상품명(읽기 전용).
  //* 활성 계약이 없으면 null 가능 → ValidateIf로 null 통과 허용.
  @Expose()
  @ApiPropertyOptional({ description: '상품명(조직 ACTIVE 계약 파생)', nullable: true })
  @ValidateIf((_, value) => value !== null && value !== undefined)
  @IsString()
  @IsOptional()
  prdName?: string | null;
}
class SubscribeFcDto extends PickType(Subscribe, []) {
  @Expose()
  @ApiPropertyOptional({
    description: '구독상태',
    enum: ['구독', '해지', '변경'],
  })
  @IsEnum(['구독', '해지', '변경'])
  @IsOptional()
  subState?: '구독' | '해지' | '변경';
}

class OrderFcDto extends PickType(Order, ['ordExpiredAt']) {}

class SalesAgencyDto extends PickType(SalesAgency, ['sagId', 'sagName']) {}

class SalesAgencyChannelDto extends PickType(SalesAgencyChannel, [
  'sacName',
  'sacCode',
]) {}

@ApiExtraModels(AgencyDto, FcDto, SubscribeFcDto, OrderFcDto, SalesAgencyDto)
export class GetFcDto {
  @Expose()
  @ApiProperty({ type: AgencyDto, description: '소속기업 정보' })
  @ValidateNested({ each: true })
  @Type(() => AgencyDto)
  @IsObject()
  agency!: AgencyDto;

  @Expose()
  @ApiProperty({ type: FcDto, description: 'FC 정보' })
  @ValidateNested({ each: true })
  @Type(() => FcDto)
  @IsObject()
  member!: FcDto;

  @Expose()
  @ApiPropertyOptional({ type: SubscribeFcDto, description: '최신구독상태' })
  @ValidateNested({ each: true })
  @Type(() => SubscribeFcDto)
  @IsObject()
  @IsOptional()
  subscribe?: SubscribeFcDto;

  @Expose()
  @ApiProperty({ type: OrderFcDto, description: '무료체험기간' })
  @ValidateNested({ each: true })
  @Type(() => OrderFcDto)
  @IsObject()
  trial!: OrderFcDto;

  @Expose()
  @ApiProperty({ type: SalesAgencyDto, description: '영업대리점' })
  @ValidateNested({ each: true })
  @Type(() => SalesAgencyDto)
  @IsObject()
  salesAgency!: SalesAgencyDto;

  @Expose()
  @ApiProperty({ type: SalesAgencyChannelDto, description: '영업대리점 채널' })
  @ValidateNested({ each: true })
  @Type(() => SalesAgencyChannelDto)
  @IsObject()
  salesAgencyChannel!: SalesAgencyChannelDto;
}

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

export class UpdateFcDto extends IntersectionType(
  PartialType(
    PickType(Member, [
      'memName',
      'memLoginId',
      'memPassword',
      'memAgency',
      'memPhone',
      'memEmail',
      //* 기업조직(task-688): 소속 조직 변경/해제용. null은 소속 해제 의도로 허용.
      'orgId',
    ]),
  ),
  PartialType(PickType(Agency, ['agcId'])),
) {}

export class CheckPasswordDto extends PickType(SignInDto, [
  'loginId',
  'password',
]) {}

//--------------------- 추천가입내역 ---------------------//
export class GetReferralSignupListDto extends PaginationDto {}

//--------------------- 푸시알림 설정 ---------------------//
export class GetPushSettingsResponseDto {
  @Expose()
  @ApiProperty({ description: '카드 사용 알림 (1=ON, 0=OFF)' })
  @IsInt()
  memPushPayment!: number;

  @Expose()
  @ApiProperty({ description: '분석 결과 알림 (1=ON, 0=OFF)' })
  @IsInt()
  memPushAnalysis!: number;

  @Expose()
  @ApiProperty({ description: '이벤트/혜택 알림 (1=ON, 0=OFF)' })
  @IsInt()
  memPushEvent!: number;

  @Expose()
  @ApiProperty({ description: '이벤트 팝업 [다음에] 96h 스누즈 여부(계정별·웹/앱 공유)' })
  eventPopupSnoozed!: boolean;
}

export class UpdatePushSettingsDto {
  @ApiPropertyOptional({ description: '카드 사용 알림 (1=ON, 0=OFF)' })
  @IsOptional()
  @IsInt()
  memPushPayment?: number;

  @ApiPropertyOptional({ description: '분석 결과 알림 (1=ON, 0=OFF)' })
  @IsOptional()
  @IsInt()
  memPushAnalysis?: number;

  @ApiPropertyOptional({ description: '이벤트/혜택 알림 (1=ON, 0=OFF)' })
  @IsOptional()
  @IsInt()
  memPushEvent?: number;
}

class ReferralSignupDto {
  @Expose()
  @ApiProperty({ description: '추천가입 회원 ID' })
  @IsInt()
  memId!: number;

  @Expose()
  @ApiProperty({ description: '추천가입 아이디' })
  memLoginId!: string;

  @Expose()
  @ApiProperty({ description: '추천가입 회원명' })
  memName!: string;

  @Expose()
  @ApiProperty({ description: '추천가입 연락처' })
  memPhone!: string;

  @Expose()
  @ApiPropertyOptional({ description: '적립머니' })
  @IsOptional()
  rewardMoney?: number;

  @Expose()
  @ApiProperty({ description: '가입일' })
  memCreatedAt!: string;
}

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

//--------------------- 회원푸시동의 관리 (관리자용) ---------------------//
export class GetPushConsentListDto extends IntersectionType(
  PaginationDto,
  DateSearchDto,
  SearchDto,
  PartialType(PickType(SalesAgency, ['sagId'])),
  PartialType(PickType(SalesAgencyChannel, ['sacCode'])),
) {
  @ApiPropertyOptional({
    description: '검색날짜 타입 (default: memCreatedAt)',
    enum: ['memCreatedAt'],
  })
  dateType = 'memCreatedAt';

  @ApiPropertyOptional({
    description: '검색조건 (default: memName)',
    enum: ['memName', 'memLoginId'],
  })
  searchKey = 'memName';

  @ApiPropertyOptional({
    description: '회원타입 (전체: "" | 일반: "MEM001" | 기업: "MEM002")',
    enum: ['', 'MEM001', 'MEM002'],
  })
  @IsOptional()
  @IsString()
  memType?: string;

  @ApiPropertyOptional({
    description: '기업 ID',
  })
  @IsOptional()
  @Transform(({ value }) => typeParser.int(value))
  @IsInt()
  agcId?: number;

  @ApiPropertyOptional({
    description: '결제 알림 여부 (전체: "" | ON: "1" | OFF: "0")',
    enum: ['', '0', '1'],
  })
  @IsOptional()
  @IsString()
  memPushPayment?: string;

  @ApiPropertyOptional({
    description: '분석 알림 여부 (전체: "" | ON: "1" | OFF: "0")',
    enum: ['', '0', '1'],
  })
  @IsOptional()
  @IsString()
  memPushAnalysis?: string;

  @ApiPropertyOptional({
    description: '이벤트/혜택 알림 여부 (전체: "" | ON: "1" | OFF: "0")',
    enum: ['', '0', '1'],
  })
  @IsOptional()
  @IsString()
  memPushEvent?: string;
}

class PushConsentDto {
  @Expose()
  @ApiProperty({ description: '회원 ID' })
  @IsInt()
  memId!: number;

  @Expose()
  @ApiPropertyOptional({ description: '영업대리점명' })
  @IsOptional()
  sagName?: string | null;

  @Expose()
  @ApiPropertyOptional({ description: '영업채널명' })
  @IsOptional()
  sacName?: string | null;

  @Expose()
  @ApiProperty({ description: '회원타입' })
  memType!: string;

  @Expose()
  @ApiPropertyOptional({ description: '기업명' })
  @IsOptional()
  agcCorporateName?: string | null;

  @Expose()
  @ApiProperty({ description: '회원아이디' })
  memLoginId!: string;

  @Expose()
  @ApiProperty({ description: '회원명' })
  memName!: string;

  @Expose()
  @ApiProperty({ description: '결제알림여부 (1=ON, 0=OFF)' })
  @IsInt()
  memPushPayment!: number;

  @Expose()
  @ApiProperty({ description: '분석알림여부 (1=ON, 0=OFF)' })
  @IsInt()
  memPushAnalysis!: number;

  @Expose()
  @ApiProperty({ description: '이벤트/혜택알림여부 (1=ON, 0=OFF)' })
  @IsInt()
  memPushEvent!: number;

  @Expose()
  @ApiProperty({ description: '가입일' })
  memCreatedAt!: string;
}

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