import { Inject, InternalServerErrorException } from '@nestjs/common';
import { CommandHandler, type ICommandHandler } from '@nestjs/cqrs';
import {
  DomainException,
  NotFoundException,
  ValidationException,
  LoggerService,
  PrismaService,
} from '@modules/shared';
import { LISTING_REPOSITORY, type IListingRepository } from '../../../domain/repositories/listing.repository';
import { AdminFeatureListingCommand } from './admin-feature-listing.command';

const ALLOWED_DURATIONS = new Set<number>([3, 7, 14, 30, 60, 90]);

export interface AdminFeatureListingResult {
  listingId: string;
  featuredUntil: string | null;
  action: 'feature' | 'unfeature';
}

@CommandHandler(AdminFeatureListingCommand)
export class AdminFeatureListingHandler
  implements ICommandHandler<AdminFeatureListingCommand>
{
  constructor(
    @Inject(LISTING_REPOSITORY) private readonly listingRepo: IListingRepository,
    private readonly prisma: PrismaService,
    private readonly logger: LoggerService,
  ) {}

  async execute(command: AdminFeatureListingCommand): Promise<AdminFeatureListingResult> {
    try {
      if (!command.reason || command.reason.trim().length < 5) {
        throw new ValidationException('Lý do phải tối thiểu 5 ký tự', { reason: command.reason });
      }

      const listing = await this.listingRepo.findById(command.listingId);
      if (!listing) {
        throw new NotFoundException('Listing', command.listingId);
      }

      let featuredUntil: Date | null;
      if (command.action === 'feature') {
        if (command.durationDays === null || !ALLOWED_DURATIONS.has(command.durationDays)) {
          throw new ValidationException('Thời lượng không hợp lệ', {
            durationDays: command.durationDays,
            allowed: Array.from(ALLOWED_DURATIONS),
          });
        }
        const now = new Date();
        const baseDate =
          listing.featuredUntil && listing.featuredUntil > now ? listing.featuredUntil : now;
        featuredUntil = new Date(baseDate.getTime() + command.durationDays * 24 * 60 * 60 * 1000);
      } else {
        featuredUntil = null;
      }

      await this.prisma.$transaction([
        this.prisma.listing.update({
          where: { id: command.listingId },
          data: {
            featuredUntil,
            featuredPackage: command.action === 'feature' ? `${command.durationDays}_days` : null,
          },
        }),
        this.prisma.adminAuditLog.create({
          data: {
            action: command.action === 'feature' ? 'LISTING_FEATURED' : 'LISTING_UNFEATURED',
            actorId: command.adminId,
            targetId: command.listingId,
            targetType: 'LISTING',
            metadata: {
              reason: command.reason,
              durationDays: command.durationDays,
              featuredUntil: featuredUntil?.toISOString() ?? null,
            },
            ipAddress: command.ipAddress,
          },
        }),
      ]);

      this.logger.log(
        `Admin ${command.action}: listing=${command.listingId}, admin=${command.adminId}, featuredUntil=${featuredUntil?.toISOString() ?? 'null'}`,
        'AdminFeatureListingHandler',
      );

      return {
        listingId: command.listingId,
        featuredUntil: featuredUntil ? featuredUntil.toISOString() : null,
        action: command.action,
      };
    } catch (error) {
      if (error instanceof DomainException) throw error;
      this.logger.error(
        `Failed to admin-feature listing: ${error instanceof Error ? error.message : error}`,
        error instanceof Error ? error.stack : undefined,
        this.constructor.name,
      );
      throw new InternalServerErrorException('Không thể cập nhật trạng thái nổi bật');
    }
  }
}
