import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, IsNull } from 'typeorm';
import { ClsService } from 'nestjs-cls';
import { TenantAwareRepository } from '../../../common/repositories/tenant-aware.repository';
import { ActivityPricingEntity } from '../../../entities/activity-pricing.entity';

@Injectable()
export class ActivityPricingRepository extends TenantAwareRepository<ActivityPricingEntity> {
  constructor(
    @InjectRepository(ActivityPricingEntity) repo: Repository<ActivityPricingEntity>,
    cls: ClsService,
  ) {
    super(repo, cls);
  }

  async findByDestinationAndCurrency(destinationId?: string, currencyId?: string): Promise<ActivityPricingEntity[]> {
    const tenantId = this.getTenantId();
    const where: any = { tenant_id: tenantId, is_deleted: false };
    if (destinationId) where.destination_id = destinationId;
    if (currencyId) where.currency_id = currencyId;

    return this.repo.find({
      where,
      relations: ['activity', 'activity.destination', 'ticket', 'currency'],
      order: { age_group: 'ASC' },
    });
  }

  async findPaginatedByActivities(query: {
    destinationId?: string; currencyId?: string; search?: string; page?: number; limit?: number;
  }) {
    const tenantId = this.getTenantId();
    const { destinationId, currencyId, search, page = 1, limit = 10 } = query;

    // Step 1: Build base query for distinct activity_ids
    const baseQb = this.repo.createQueryBuilder('ap')
      .where('ap.tenant_id = :tenantId AND ap.is_deleted = false', { tenantId });

    if (destinationId) baseQb.andWhere('ap.destination_id = :destinationId', { destinationId });
    if (currencyId) baseQb.andWhere('ap.currency_id = :currencyId', { currencyId });
    if (search) {
      baseQb.leftJoin('ap.activity', 'act')
        .andWhere('act.name ILIKE :search', { search: `%${search}%` });
    }

    // Count distinct activities
    const countQb = baseQb.clone().select('COUNT(DISTINCT ap.activity_id)', 'cnt');
    const countResult = await countQb.getRawOne();
    const totalActivities = parseInt(countResult?.cnt || '0', 10);

    // Get paginated distinct activity_ids
    const activityRows = await baseQb
      .select('ap.activity_id', 'activity_id')
      .groupBy('ap.activity_id')
      .addSelect('MAX(ap.created_at)', 'latest')
      .orderBy('latest', 'DESC')
      .offset((page - 1) * limit)
      .limit(limit)
      .getRawMany();

    const activityIds = activityRows.map((r: any) => r.activity_id);
    if (activityIds.length === 0) {
      return { items: [], meta: { total: totalActivities, page, limit, totalPages: Math.ceil(totalActivities / limit) } };
    }

    // Step 2: Fetch all pricing rows for those activities
    const items = await this.repo.find({
      where: activityIds.map((id: string) => ({
        tenant_id: tenantId, activity_id: id, is_deleted: false,
        ...(currencyId ? { currency_id: currencyId } : {}),
      })),
      relations: ['activity', 'activity.destination', 'ticket', 'currency'],
      order: { age_group: 'ASC' },
    });

    return { items, meta: { total: totalActivities, page, limit, totalPages: Math.ceil(totalActivities / limit) } };
  }

  async findByActivity(activityId: string): Promise<ActivityPricingEntity[]> {
    const tenantId = this.getTenantId();
    return this.repo.find({
      where: { activity_id: activityId, tenant_id: tenantId, is_deleted: false } as any,
    });
  }

  async findExisting(activityId: string, ticketId: string | null, ageGroup: string, currencyId: string): Promise<ActivityPricingEntity | null> {
    const tenantId = this.getTenantId();
    const where: any = { activity_id: activityId, age_group: ageGroup, currency_id: currencyId, tenant_id: tenantId, is_deleted: false };
    if (ticketId) {
      where.ticket_id = ticketId;
    } else {
      where.ticket_id = IsNull();
    }
    return this.repo.findOne({ where });
  }

  async findSoftDeleted(activityId: string, ticketId: string | null, ageGroup: string, currencyId: string): Promise<ActivityPricingEntity | null> {
    const tenantId = this.getTenantId();
    const where: any = { activity_id: activityId, age_group: ageGroup, currency_id: currencyId, tenant_id: tenantId, is_deleted: true };
    if (ticketId) {
      where.ticket_id = ticketId;
    } else {
      where.ticket_id = IsNull();
    }
    return this.repo.findOne({ where });
  }

  async reactivate(id: string, data: Partial<ActivityPricingEntity>): Promise<void> {
    const userId = this.getUserId();
    await this.repo.update(id, { ...data, is_deleted: false, updated_by: userId } as any);
  }
}
