import { InternalServerErrorException } from '@nestjs/common';
import { CommandHandler, CommandBus, ICommandHandler, QueryBus } from '@nestjs/cqrs';
import { createId } from '@paralleldrive/cuid2';
import { SavedSearch, Prisma } from '@prisma/client';
import { DomainException, ValidationException, PrismaService, LoggerService } from '@modules/shared';
import { CheckQuotaQuery, QuotaCheckResult, MeterUsageCommand } from '@modules/subscriptions';
import { CreateSavedSearchCommand } from './create-saved-search.command';

export interface CreateSavedSearchResult {
  id: string;
  name: string;
  filters: unknown;
  alertEnabled: boolean;
  createdAt: Date;
}

@CommandHandler(CreateSavedSearchCommand)
export class CreateSavedSearchHandler implements ICommandHandler<CreateSavedSearchCommand> {
  constructor(
    private readonly prisma: PrismaService,
    private readonly queryBus: QueryBus,
    private readonly commandBus: CommandBus,
    private readonly logger: LoggerService,
  ) {}

  async execute(command: CreateSavedSearchCommand): Promise<CreateSavedSearchResult> {
    try {
      // Validate name
      if (!command.name || command.name.trim().length === 0) {
        throw new ValidationException('Tên tìm kiếm không được để trống');
      }

      if (command.name.trim().length > 100) {
        throw new ValidationException('Tên tìm kiếm không được vượt quá 100 ký tự');
      }

      // Check quota
      const quotaResult: QuotaCheckResult = await this.queryBus.execute(
        new CheckQuotaQuery(command.userId, 'searches_saved'),
      );

      if (!quotaResult.allowed) {
        throw new ValidationException(
          `Bạn đã đạt giới hạn ${quotaResult.limit} tìm kiếm đã lưu. Vui lòng nâng cấp gói để tiếp tục.`,
        );
      }

      const id = createId();
      const savedSearch: SavedSearch = await this.prisma.savedSearch.create({
        data: {
          id,
          userId: command.userId,
          name: command.name.trim(),
          filters: command.filters as Prisma.InputJsonValue,
          alertEnabled: command.alertEnabled,
        },
      });

      // Best-effort usage metering
      try {
        await this.commandBus.execute(
          new MeterUsageCommand(command.userId, 'searches_saved', 1),
        );
      } catch (err) {
        this.logger.warn(
          `Usage metering failed for saved search: ${err instanceof Error ? err.message : String(err)}`,
          'CreateSavedSearchHandler',
        );
      }

      this.logger.log(`Saved search created: id=${id}, user=${command.userId}`, 'CreateSavedSearchHandler');

      return {
        id: savedSearch.id,
        name: savedSearch.name,
        filters: savedSearch.filters,
        alertEnabled: savedSearch.alertEnabled,
        createdAt: savedSearch.createdAt,
      };
    } catch (error) {
      if (error instanceof DomainException) throw error;
      this.logger.error(
        `Failed to create saved search: ${error instanceof Error ? error.message : error}`,
        error instanceof Error ? error.stack : undefined,
        this.constructor.name,
      );
      throw new InternalServerErrorException('Không thể tạo tìm kiếm đã lưu');
    }
  }
}
