import {
  ApiProperty,
  ApiPropertyOptional,
  IntersectionType,
} from '@nestjs/swagger';
import { Expose, Type } from 'class-transformer';
import {
  IsEnum,
  IsIn,
  IsInt,
  IsNotEmpty,
  IsOptional,
  IsString,
  Max,
  Min,
  NotEquals,
  ValidateIf,
} from 'class-validator';
import { AUDIT_REASON } from '../audit/audit-reason';
import { DateSearchDto, PaginationDto, SearchDto } from '../common/common.dto';
import {
  MoneyCorpEntity,
  MoneyCorpSummaryEntity,
  MoneyChargeRequestEntity,
  MoneyIssueEntity,
  MoneyIssueTargetEntity,
  MoneyPaymentCancelEntity,
  MoneyPaymentEntity,
  MoneyRefundEntity,
  MoneyWalletEntity,
  MoneyWalletSummaryEntity
} from './money.entity';

// ============================================================================
// 공통 Enum
// ============================================================================

export enum MoneyIssueType {
  EARN = 'EARN',
  EARN_RECOVERY = 'EARN_RECOVERY',
}

export enum MoneyGrantType {
  GRANT = 'GRANT',
  GRANT_RECOVERY = 'GRANT_RECOVERY',
}

export enum MoneyTargetType {
  ALL = 'ALL',
  SUBSCRIPTION = 'SUBSCRIPTION',
  SPECIFIC = 'SPECIFIC',
}

export enum MoneyMemberType {
  GENERAL = 'GENERAL',
  CORP = 'CORP',
}

export enum MoneyPaymentStatus {
  COMPLETED = 'COMPLETED',
  CANCELLED = 'CANCELLED',
  PARTIAL_CANCELLED = 'PARTIAL_CANCELLED',
  //* 취소가 PG 응답을 기다리거나 PG 결과를 모르는 동안의 결제 단위 예약 표지 (cancelGeneralPaymentReserved).
  CANCELLING = 'CANCELLING',
}

export enum MoneyChargeRequestStatus {
  REQUESTED = 'REQUESTED',
  APPROVED = 'APPROVED',
  REJECTED = 'REJECTED',
  CANCELED = 'CANCELED',
}

export enum MoneyRefundStatus {
  PENDING = 'PENDING',
  APPROVED = 'APPROVED',
  REJECTED = 'REJECTED',
}

export enum MoneyWalletType {
  EARN = 'EARN',
  EARN_RECOVERY = 'EARN_RECOVERY',
  GRANT = 'GRANT',
  GRANT_RECOVERY = 'GRANT_RECOVERY',
  CHARGE = 'CHARGE',
  CANCEL = 'CANCEL',
  REFUND_REQ = 'REFUND_REQ',
  REFUND_OK = 'REFUND_OK',
  REFUND_NO = 'REFUND_NO',
  USE = 'USE',
  USE_CANCEL = 'USE_CANCEL',
  EXPIRE = 'EXPIRE',
}

export enum MoneySourceType {
  EARN = 'EARN',
  GRANT = 'GRANT',
  CHARGE = 'CHARGE',
}

export const MAX_MONEY_CHANGE_AMOUNT = 2_147_483_647;
export const MAX_MONEY_BALANCE_AMOUNT = 4_294_967_295;

export enum MoneyMoneyType {
  BASIC = 'BASIC',
  PURCHASE = 'PURCHASE',
  AGENCY = 'AGENCY',
}

export enum MoneyCancelType {
  USER = 'USER',
  ADMIN = 'ADMIN',
}

export enum MoneyUsageType {
  DEDUCT = 'DEDUCT',
  RESTORE = 'RESTORE',
}

// ============================================================================
// 관리자 - 회원머니 관리 DTO
// ============================================================================

export class GetMoneyIssueListDto extends IntersectionType(
  PaginationDto,
  IntersectionType(DateSearchDto, SearchDto),
) {
  @Expose()
  @ApiPropertyOptional({ description: '대상구분', enum: MoneyTargetType })
  @IsEnum(MoneyTargetType)
  @IsOptional()
  targetType?: MoneyTargetType;

  //* 기업 필터 — corp 로그인 시 컨트롤러에서 자기 기업(agcId)으로 강제됨
  @Expose()
  @ApiPropertyOptional({ description: '기업 ID' })
  @Type(() => Number)
  @IsInt()
  @IsOptional()
  agcId?: number;
}

export class GetMoneyIssueListResponseDto {
  @Expose()
  @ApiProperty({ description: '총 개수' })
  count!: number;

  @Expose()
  @ApiProperty({ type: [MoneyIssueEntity], description: '목록' })
  @Type(() => MoneyIssueEntity)
  list!: MoneyIssueEntity[];
}

export class CreateMoneyIssueDto {
  @ApiProperty({ description: '구분', enum: MoneyIssueType })
  @IsEnum(MoneyIssueType)
  mniType!: MoneyIssueType;

  @ApiProperty({ description: '회원구분', enum: MoneyMemberType })
  @IsEnum(MoneyMemberType)
  mniMemberType!: MoneyMemberType;

  @ApiPropertyOptional({ description: '기업 ID (기업회원 대상 시)' })
  @IsOptional()
  @IsInt()
  agcId?: number;

  @ApiProperty({ description: '대상구분', enum: MoneyTargetType })
  @IsEnum(MoneyTargetType)
  mniTargetType!: MoneyTargetType;

  @ApiPropertyOptional({ description: '특정회원 ID 목록 (SPECIFIC 시)', type: [Number] })
  @IsOptional()
  @Type(() => Number)
  memberIds?: number[];

  @ApiProperty({ description: '머니명' })
  @IsNotEmpty()
  @IsString()
  mniTitle!: string;

  @ApiPropertyOptional({ description: '사유' })
  @IsOptional()
  @IsString()
  mniReason?: string;

  @ApiProperty({ description: '적용머니 (양수: 적립, 음수: 회수)' })
  @IsInt()
  @NotEquals(0)
  @Min(-MAX_MONEY_CHANGE_AMOUNT)
  @Max(MAX_MONEY_CHANGE_AMOUNT)
  mniAmount!: number;

  @ApiPropertyOptional({ description: '유효기간 설정 여부' })
  @IsOptional()
  @Type(() => Number)
  mniHasExpiry?: number;

  @ApiPropertyOptional({ description: '유효기간 (일)' })
  @IsOptional()
  @Type(() => Number)
  mniExpiryDays?: number;

  @ApiProperty({ description: '사유 유형', enum: AUDIT_REASON.map((r) => r.code) })
  @IsString()
  reasonCode!: string;
}

export class GetMoneyIssueDetailDto extends PaginationDto {}

export class GetMoneyIssueDetailResponseDto {
  @Expose()
  @ApiProperty({ type: MoneyIssueEntity, description: '적립 정보' })
  @Type(() => MoneyIssueEntity)
  issue!: MoneyIssueEntity;

  @Expose()
  @ApiProperty({ description: '총 개수' })
  count!: number;

  @Expose()
  @ApiProperty({ type: [MoneyIssueTargetEntity], description: '대상 회원 목록' })
  @Type(() => MoneyIssueTargetEntity)
  list!: MoneyIssueTargetEntity[];
}

// ============================================================================
// 관리자 - 기업머니 관리 DTO
// ============================================================================

export class GetMoneyCorpListDto extends IntersectionType(
  PaginationDto,
  IntersectionType(DateSearchDto, SearchDto),
) {
  @ApiPropertyOptional({ description: '영업대리점명' })
  @IsOptional()
  @IsString()
  sagName?: string;
}

export class CreateMoneyCorpDto {
  @ApiProperty({ description: '기업 ID' })
  @IsInt()
  agcId!: number;

  @ApiProperty({ description: '머니명' })
  @IsNotEmpty()
  @IsString()
  mcpTitle!: string;

  @ApiPropertyOptional({ description: '사유' })
  @IsOptional()
  @IsString()
  mcpReason?: string;

  @ApiProperty({ description: '금액 (양수: 충전, 음수: 차감)' })
  @IsInt()
  @NotEquals(0)
  @Min(-MAX_MONEY_CHANGE_AMOUNT)
  @Max(MAX_MONEY_CHANGE_AMOUNT)
  mcpAmount!: number;

  @ApiProperty({ description: '사유 유형', enum: AUDIT_REASON.map((r) => r.code) })
  @IsString()
  reasonCode!: string;
}

export class GetMoneyCorpHistoryDto extends IntersectionType(
  PaginationDto,
  IntersectionType(DateSearchDto, SearchDto),
) {
  @ApiPropertyOptional({ description: '구분 (EARN/EARN_RECOVERY/GRANT/GRANT_RECOVERY)' })
  @IsOptional()
  @IsString()
  mcpType?: string;

  @ApiPropertyOptional({ description: '대상구분', enum: MoneyTargetType })
  @IsOptional()
  @IsEnum(MoneyTargetType)
  targetType?: MoneyTargetType;
}

export class GetMoneyCorpHistoryResponseDto {
  @Expose()
  @ApiProperty({ description: '총 개수' })
  count!: number;

  @Expose()
  @ApiProperty({ type: [MoneyCorpEntity], description: '목록' })
  @Type(() => MoneyCorpEntity)
  list!: MoneyCorpEntity[];

  @Expose()
  @ApiProperty({ type: MoneyCorpSummaryEntity, description: '요약 정보' })
  @Type(() => MoneyCorpSummaryEntity)
  summary!: MoneyCorpSummaryEntity;
}

// ============================================================================
// 관리자/기업관리자 - 기업머니 충전요청 DTO
// ============================================================================

export class GetMoneyChargeRequestListDto extends IntersectionType(
  PaginationDto,
  IntersectionType(DateSearchDto, SearchDto),
) {
  @ApiPropertyOptional({ description: '기업 ID' })
  @IsOptional()
  @Type(() => Number)
  @IsInt()
  agcId?: number;

  @ApiPropertyOptional({ description: '상태', enum: MoneyChargeRequestStatus })
  @IsOptional()
  @IsEnum(MoneyChargeRequestStatus)
  status?: MoneyChargeRequestStatus;

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

export class GetMoneyChargeRequestListResponseDto {
  @Expose()
  @ApiProperty({ description: '총 개수' })
  count!: number;

  @Expose()
  @ApiProperty({ type: [MoneyChargeRequestEntity], description: '목록' })
  @Type(() => MoneyChargeRequestEntity)
  list!: MoneyChargeRequestEntity[];
}

export class CreateMoneyChargeRequestDto {
  @ApiProperty({ description: '요청금액' })
  @Type(() => Number)
  @IsInt()
  @Min(10000)
  @Max(MAX_MONEY_CHANGE_AMOUNT)
  mcrAmount!: number;

  @ApiPropertyOptional({ description: '요청명' })
  @IsOptional()
  @IsString()
  mcrTitle?: string;

  @ApiPropertyOptional({ description: '요청 사유' })
  @IsOptional()
  @IsString()
  mcrReason?: string;
}

export class ProcessMoneyChargeRequestDto {
  @ApiProperty({ description: '충전요청 ID' })
  @Type(() => Number)
  @IsInt()
  mcrId!: number;

  @ApiProperty({ description: '처리 액션', enum: ['APPROVE', 'REJECT'] })
  @IsIn(['APPROVE', 'REJECT'])
  action!: 'APPROVE' | 'REJECT';

  @ApiPropertyOptional({ description: '관리자 메모' })
  @IsOptional()
  @IsString()
  adminMemo?: string;

  @ApiPropertyOptional({ description: '반려 사유' })
  @IsOptional()
  @IsString()
  rejectedReason?: string;

  //* 사유 유형은 승인만 요구한다 — 반려는 사유 텍스트 필수가 이미 있고 사유 유형·적재는
  //*  트랜잭션화와 함께 붙는다(계획 M8 D5·UI9). 판정의 정본은 서비스의 assertInterventionReason 이다.
  @ApiPropertyOptional({ description: '사유 유형 (승인 시 필수)', enum: AUDIT_REASON.map((r) => r.code) })
  @ValidateIf((o) => o.action === 'APPROVE')
  @IsString()
  reasonCode?: string;
}

export class CancelMoneyChargeRequestDto {
  @ApiProperty({ description: '충전요청 ID' })
  @Type(() => Number)
  @IsInt()
  mcrId!: number;
}

// ============================================================================
// 관리자 - 기업회원머니 관리 DTO
// ============================================================================

export class CreateMoneyGrantDto {
  @ApiProperty({ description: '기업 ID' })
  @IsInt()
  agcId!: number;

  @ApiProperty({ description: '구분', enum: MoneyGrantType })
  @IsEnum(MoneyGrantType)
  mngType!: MoneyGrantType;

  @ApiProperty({ description: '대상구분', enum: MoneyTargetType })
  @IsEnum(MoneyTargetType)
  mngTargetType!: MoneyTargetType;

  @ApiPropertyOptional({ description: '특정회원 ID 목록 (SPECIFIC 시)', type: [Number] })
  @IsOptional()
  @Type(() => Number)
  memberIds?: number[];

  @ApiProperty({ description: '머니명' })
  @IsNotEmpty()
  @IsString()
  mngTitle!: string;

  @ApiPropertyOptional({ description: '사유' })
  @IsOptional()
  @IsString()
  mngReason?: string;

  @ApiProperty({ description: '적용머니' })
  @IsInt()
  @Min(1)
  @Max(MAX_MONEY_CHANGE_AMOUNT)
  mngAmount!: number;

  @ApiPropertyOptional({ description: '유효기간 설정 여부' })
  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @IsIn([0, 1])
  mngHasExpiry?: number;

  @ApiPropertyOptional({ description: '유효기간 (일)' })
  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  mngExpiryDays?: number;

  //* 기업·조직관리자(corp)는 보내지 않는다 — 서버가 방향으로 배분/회수를 정한다(corpGrantReason).
  //*  관리자·영업대리점은 서비스의 assertInterventionReason 이 여전히 필수로 판정한다.
  @ApiPropertyOptional({
    description: '사유 유형 (기업·조직관리자는 생략)',
    enum: AUDIT_REASON.map((r) => r.code),
  })
  @IsOptional()
  @IsString()
  reasonCode?: string;
}

export class CreateMoneyGrantSingleDto {
  @ApiProperty({ description: '기업 ID' })
  @IsInt()
  agcId!: number;

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

  @ApiProperty({ description: '머니명' })
  @IsNotEmpty()
  @IsString()
  mngTitle!: string;

  @ApiPropertyOptional({ description: '사유' })
  @IsOptional()
  @IsString()
  mngReason?: string;

  @ApiProperty({ description: '적용머니 (양수: 지급, 음수: 회수)' })
  @IsInt()
  @NotEquals(0)
  @Min(-MAX_MONEY_CHANGE_AMOUNT)
  @Max(MAX_MONEY_CHANGE_AMOUNT)
  mngAmount!: number;

  @ApiPropertyOptional({ description: '유효기간 설정 여부' })
  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @IsIn([0, 1])
  mngHasExpiry?: number;

  @ApiPropertyOptional({ description: '유효기간 (일)' })
  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  mngExpiryDays?: number;

  //* 기업·조직관리자(corp)는 보내지 않는다 — 서버가 방향으로 배분/회수를 정한다(corpGrantReason).
  //*  관리자·영업대리점은 서비스의 assertInterventionReason 이 여전히 필수로 판정한다.
  @ApiPropertyOptional({
    description: '사유 유형 (기업·조직관리자는 생략)',
    enum: AUDIT_REASON.map((r) => r.code),
  })
  @IsOptional()
  @IsString()
  reasonCode?: string;
}

// ============================================================================
// 관리자 - 내역관리 DTO
// ============================================================================

export class GetMoneyWalletListDto extends IntersectionType(
  PaginationDto,
  IntersectionType(DateSearchDto, SearchDto),
) {
  @ApiPropertyOptional({ description: '영업대리점명' })
  @IsOptional()
  @IsString()
  sagName?: string;

  @ApiPropertyOptional({ description: '회원타입', enum: MoneyMemberType })
  @IsOptional()
  @IsEnum(MoneyMemberType)
  memType?: MoneyMemberType;

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

  @ApiPropertyOptional({ description: '구분' })
  @IsOptional()
  @IsString()
  mwlType?: string;

  //* 기업관리자 스코프(서버 내부 주입, 클라 미노출) — 자기 기업 회원머니만
  @IsOptional()
  @IsInt()
  agcId?: number;

  //* 조직관리자 부분트리 스코프(서버 내부 주입, 클라 미노출) — org_path LIKE prefix
  @IsOptional()
  @IsString()
  orgPath?: string;
}

export class GetMoneyWalletListResponseDto {
  @Expose()
  @ApiProperty({ description: '총 개수' })
  count!: number;

  @Expose()
  @ApiProperty({ type: [MoneyWalletEntity], description: '목록' })
  @Type(() => MoneyWalletEntity)
  list!: MoneyWalletEntity[];
}

// 회원별 내역 조회 DTO
export class GetMemberWalletHistoryDto extends PaginationDto {
  @ApiPropertyOptional({ description: '구분' })
  @IsOptional()
  @IsString()
  mwlType?: string;

  @ApiPropertyOptional({ description: '시작일' })
  @IsOptional()
  @IsString()
  startDate?: string;

  @ApiPropertyOptional({ description: '종료일' })
  @IsOptional()
  @IsString()
  endDate?: string;

  @ApiPropertyOptional({ description: '검색키' })
  @IsOptional()
  @IsString()
  searchKey?: string;

  @ApiPropertyOptional({ description: '검색어' })
  @IsOptional()
  @IsString()
  searchText?: string;
}

export class GetMemberWalletHistoryResponseDto {
  @Expose()
  @ApiProperty({ description: '총 개수' })
  count!: number;

  @Expose()
  @ApiProperty({ type: [MoneyWalletEntity], description: '목록' })
  @Type(() => MoneyWalletEntity)
  list!: MoneyWalletEntity[];

  @Expose()
  @ApiProperty({ type: MoneyWalletSummaryEntity, description: '요약 정보' })
  @Type(() => MoneyWalletSummaryEntity)
  summary!: MoneyWalletSummaryEntity;
}

// ============================================================================
// 관리자 - 결제관리 DTO
// ============================================================================

export class GetMoneyPaymentListDto extends IntersectionType(
  PaginationDto,
  IntersectionType(DateSearchDto, SearchDto),
) {
  @ApiPropertyOptional({ description: '영업대리점명' })
  @IsOptional()
  @IsString()
  sagName?: string;

  @ApiPropertyOptional({ description: '회원타입', enum: MoneyMemberType })
  @IsOptional()
  @IsEnum(MoneyMemberType)
  memType?: MoneyMemberType;

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

  @ApiPropertyOptional({ description: '결제상태', enum: MoneyPaymentStatus })
  @IsOptional()
  @IsEnum(MoneyPaymentStatus)
  mpyStatus?: MoneyPaymentStatus;
}

export class GetMoneyPaymentListResponseDto {
  @Expose()
  @ApiProperty({ description: '총 개수' })
  count!: number;

  @Expose()
  @ApiProperty({ type: [MoneyPaymentEntity], description: '목록' })
  @Type(() => MoneyPaymentEntity)
  list!: MoneyPaymentEntity[];
}

export class GetMoneyPaymentDetailResponseDto {
  @Expose()
  @ApiProperty({ type: MoneyPaymentEntity, description: '결제 정보' })
  @Type(() => MoneyPaymentEntity)
  payment!: MoneyPaymentEntity;

  @Expose()
  @ApiProperty({ type: [MoneyPaymentCancelEntity], description: '취소 이력' })
  @Type(() => MoneyPaymentCancelEntity)
  cancels!: MoneyPaymentCancelEntity[];
}

// 이용내역 아이템 (프론트엔드 형식)
export class PaymentUsageListItemDto {
  @Expose()
  @ApiProperty({ description: '이용내역 ID' })
  usageMthId!: number;

  @Expose()
  @ApiProperty({ description: '사용금액' })
  mumAmount!: number;

  @Expose()
  @ApiPropertyOptional({ description: '설명' })
  mthDescription?: string | null;

  @Expose()
  @ApiProperty({ description: '생성일시' })
  mthCreatedAt!: string;

  @Expose()
  @ApiPropertyOptional({ description: '타입 (USE / USE_CANCEL)' })
  mthType?: string;
}

// 취소내역 아이템 (프론트엔드 형식)
export class PaymentCancelListItemDto {
  @Expose()
  @ApiProperty({ description: '취소내역 ID' })
  mthId!: number;

  @Expose()
  @ApiProperty({ description: '취소금액' })
  mthAmount!: number;

  @Expose()
  @ApiPropertyOptional({ description: '취소사유' })
  mthDescription?: string | null;

  @Expose()
  @ApiProperty({ description: '생성일시' })
  mthCreatedAt!: string;
}

// 환불내역 아이템 (프론트엔드 형식)
export class PaymentRefundListItemDto {
  @Expose()
  @ApiProperty({ description: '환불 ID' })
  mrfId!: number;

  @Expose()
  @ApiProperty({ description: '이 결제에서 차감된 금액' })
  mrfAmount!: number;

  @Expose()
  @ApiPropertyOptional({ description: '전체 환불 신청 금액' })
  mrfTotalAmount?: number;

  @Expose()
  @ApiProperty({ description: '환불 상태' })
  mrfStatus!: string;

  @Expose()
  @ApiPropertyOptional({ description: '환불 사유' })
  mrfReason?: string | null;

  @Expose()
  @ApiPropertyOptional({ description: '관리자 메모' })
  mrfAdminMemo?: string | null;

  @Expose()
  @ApiPropertyOptional({ description: '처리일시' })
  mrfProcessedAt?: string | null;

  @Expose()
  @ApiProperty({ description: '생성일시' })
  mrfCreatedAt!: string;
}

// wallet 정보 (프론트엔드 형식)
export class PaymentWalletInfoDto {
  @Expose()
  @ApiProperty({ description: '원래 금액' })
  mwlOriginalAmount!: number;

  @Expose()
  @ApiProperty({ description: '잔액' })
  mwlBalance!: number;
}

export class GetMoneyPaymentUsageResponseDto {
  @Expose()
  @ApiProperty({ type: MoneyPaymentEntity, description: '결제 정보' })
  @Type(() => MoneyPaymentEntity)
  payment!: MoneyPaymentEntity;

  @Expose()
  @ApiProperty({ type: [PaymentUsageListItemDto], description: '이용내역' })
  @Type(() => PaymentUsageListItemDto)
  usageList!: PaymentUsageListItemDto[];

  @Expose()
  @ApiProperty({ type: [PaymentCancelListItemDto], description: '취소내역' })
  @Type(() => PaymentCancelListItemDto)
  cancelList!: PaymentCancelListItemDto[];

  @Expose()
  @ApiProperty({ type: [PaymentRefundListItemDto], description: '환불내역' })
  @Type(() => PaymentRefundListItemDto)
  refundList!: PaymentRefundListItemDto[];

  @Expose()
  @ApiPropertyOptional({ type: PaymentWalletInfoDto, description: 'wallet 정보' })
  @Type(() => PaymentWalletInfoDto)
  wallet?: PaymentWalletInfoDto | null;

  @Expose()
  @ApiProperty({ description: '사용 금액 합계' })
  useOnlyAmount!: number;
}

export class CancelMoneyPaymentDto {
  @ApiProperty({ description: '결제 ID' })
  @IsInt()
  mpyId!: number;

  @ApiPropertyOptional({ description: '취소 사유' })
  @IsOptional()
  @IsString()
  mpcReason?: string;

  @ApiPropertyOptional({
    description:
      '남은 금액 전부 취소 시 그 금액 (원천 잔여와 다르면 거절, 미입력 시 전액취소)',
  })
  @IsOptional()
  @IsInt()
  @Min(1)
  cancelAmount?: number;
}

export class ResolveCancellingPaymentDto {
  @ApiProperty({ description: '결제 ID' })
  @IsInt()
  mpyId!: number;
}

// ============================================================================
// 관리자 - 환불관리 DTO
// ============================================================================

export class GetMoneyRefundListDto extends IntersectionType(
  PaginationDto,
  IntersectionType(DateSearchDto, SearchDto),
) {
  @ApiPropertyOptional({ description: '영업대리점명' })
  @IsOptional()
  @IsString()
  sagName?: string;

  @ApiPropertyOptional({ description: '회원타입', enum: MoneyMemberType })
  @IsOptional()
  @IsEnum(MoneyMemberType)
  memType?: MoneyMemberType;

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

  @ApiPropertyOptional({ description: '환불상태', enum: MoneyRefundStatus })
  @IsOptional()
  @IsEnum(MoneyRefundStatus)
  mrfStatus?: MoneyRefundStatus;
}

export class GetMoneyRefundListResponseDto {
  @Expose()
  @ApiProperty({ description: '총 개수' })
  count!: number;

  @Expose()
  @ApiProperty({ type: [MoneyRefundEntity], description: '목록' })
  @Type(() => MoneyRefundEntity)
  list!: MoneyRefundEntity[];
}

export class GetMoneyRefundDetailResponseDto {
  @Expose()
  @ApiProperty({ type: MoneyRefundEntity, description: '환불 정보' })
  @Type(() => MoneyRefundEntity)
  refund!: MoneyRefundEntity;
}

export class ProcessMoneyRefundDto {
  @ApiProperty({ description: '환불 ID' })
  @IsInt()
  mrfId!: number;

  @ApiProperty({ description: '처리 유형', enum: ['APPROVED', 'REJECTED'] })
  @IsEnum(['APPROVED', 'REJECTED'])
  action!: 'APPROVED' | 'REJECTED';

  @ApiPropertyOptional({ description: '관리자 메모 (반려 시 필수)' })
  @IsOptional()
  @IsString()
  mrfAdminMemo?: string;
}

// ============================================================================
// 유저 - 머니 조회 DTO
// ============================================================================

export class GetUserMoneyResponseDto {
  @Expose()
  @ApiProperty({ description: '보유 머니 총액' })
  totalMoney!: number;

  @Expose()
  @ApiProperty({ description: '기본머니' })
  memMoney!: number;

  @Expose()
  @ApiProperty({ description: '충전머니' })
  memPurchaseMoney!: number;

  @Expose()
  @ApiProperty({ description: '기업머니' })
  memAgencyMoney!: number;
}

export class GetUserMoneyHistoryDto extends PaginationDto {
  @ApiPropertyOptional({ description: '탭 필터 (all/charge/use)' })
  @IsOptional()
  @IsString()
  tab?: string;

  @ApiPropertyOptional({ description: '기간 (1w/1m/3m/6m)' })
  @IsOptional()
  @IsString()
  period?: string;
}

export class GetUserMoneyHistoryResponseDto {
  @Expose()
  @ApiProperty({ description: '총 개수' })
  count!: number;

  @Expose()
  @ApiProperty({ type: [MoneyWalletEntity], description: '목록' })
  @Type(() => MoneyWalletEntity)
  list!: MoneyWalletEntity[];

  @Expose()
  @ApiProperty({ description: '보유 머니 총액' })
  totalMoney!: number;
}

// ============================================================================
// 유저 - 머니 충전 DTO
// ============================================================================

export class RequestChargeDto {
  @ApiProperty({ description: '충전 금액' })
  @IsInt()
  @Min(10000)
  amount!: number;

  @ApiProperty({ description: '상품명', required: false })
  @IsString()
  @IsOptional()
  goodsName?: string;
}

export class RequestChargeResponseDto {
  @Expose()
  @ApiProperty({ description: '가맹점 ID' })
  Mid!: string;

  @Expose()
  @ApiProperty({ description: '전문생성일시' })
  EdiDate!: string;

  @Expose()
  @ApiProperty({ description: '암호화 데이터' })
  EncryptData!: string;

  @Expose()
  @ApiProperty({ description: '주문번호' })
  Moid!: string;

  @Expose()
  @ApiProperty({ description: '결제 금액' })
  Amt!: number;

  @Expose()
  @ApiProperty({ description: '부가세' })
  TaxAmt!: number;

  @Expose()
  @ApiProperty({ description: '세액' })
  VatAmt!: number;

  @Expose()
  @ApiProperty({ description: '비과세' })
  TaxFreeAmt!: number;

  @Expose()
  @ApiProperty({ description: '상품명' })
  GoodsName!: string;

  @Expose()
  @ApiProperty({ description: '구매자명' })
  BuyerName!: string;

  @Expose()
  @ApiProperty({ description: '구매자 연락처' })
  BuyerTel!: string;

  @Expose()
  @ApiProperty({ description: '구매자 이메일' })
  BuyerEmail!: string;
}

// ============================================================================
// 유저 - 결제 취소 DTO
// ============================================================================

export class CheckPaymentCancellableResponseDto {
  @Expose()
  @ApiProperty({ description: '취소 가능 여부' })
  cancellable!: boolean;

  @Expose()
  @ApiProperty({ description: '취소 불가 사유' })
  reason?: string;

  @Expose()
  @ApiProperty({ type: MoneyPaymentEntity, description: '결제 정보' })
  @Type(() => MoneyPaymentEntity)
  payment?: MoneyPaymentEntity;
}

export class CancelChargeDto {
  @ApiProperty({ description: '결제 TID' })
  @IsNotEmpty()
  @IsString()
  mpyTid!: string;

  @ApiProperty({ description: '취소 사유' })
  @IsNotEmpty()
  @IsString()
  mpcReason!: string;
}

// ============================================================================
// 유저 - 환불 신청 DTO
// ============================================================================

export class GetRefundInfoResponseDto {
  @Expose()
  @ApiProperty({ description: '환불 가능 금액' })
  refundableAmount!: number;

  @Expose()
  @ApiProperty({ description: '보유 머니 총액' })
  totalMoney!: number;
}

export class RequestRefundDto {
  @ApiProperty({ description: '환불 요청 금액' })
  @IsInt()
  @Min(1000)
  mrfAmount!: number;

  @ApiProperty({ description: '은행명' })
  @IsNotEmpty()
  @IsString()
  mrfBankName!: string;

  @ApiProperty({ description: '계좌번호' })
  @IsNotEmpty()
  @IsString()
  mrfAccountNumber!: string;

  @ApiProperty({ description: '예금주' })
  @IsNotEmpty()
  @IsString()
  mrfAccountHolder!: string;

  @ApiProperty({ description: '환불 사유' })
  @IsNotEmpty()
  @IsString()
  mrfReason!: string;
}

export class RequestRefundResponseDto {
  @Expose()
  @ApiProperty({ description: '환불 ID' })
  mrfId!: number;

  @Expose()
  @ApiProperty({ description: '환불 요청 금액' })
  mrfAmount!: number;

  @Expose()
  @ApiProperty({ description: '수수료' })
  mrfFee!: number;

  @Expose()
  @ApiProperty({ description: '실 환불 금액' })
  mrfActualAmount!: number;
}
