import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { FindOptionsOrder, Repository } from 'typeorm';
import { ClsService } from 'nestjs-cls';
import { TenantAwareRepository } from '../../../common/repositories/tenant-aware.repository';
import {
  ActivityTicketBatchEntity,
  TicketBatchStatus,
} from '../../../entities/activity-ticket-batch.entity';

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

  async findAllPaginated(params: {
    page?: number;
    limit?: number;
    search?: string;
    activity_id?: string;
    status?: TicketBatchStatus;
  }) {
    return this.findPaginated({
      page: params.page,
      limit: params.limit,
      search: params.search,
      searchColumns: ['ticket_type', 'age_group', 'notes'],
      relations: ['activity', 'supplier'],
      order: { created_at: 'DESC' },
      where: {
        ...(params.activity_id ? { activity_id: params.activity_id } : {}),
        ...(params.status ? { status: params.status } : {}),
      },
    });
  }

  async findByIdWithItems(id: string): Promise<ActivityTicketBatchEntity | null> {
    const tenantId = this.getTenantId();
    return this.repo.findOne({
      where: { id, tenant_id: tenantId, is_deleted: false },
      relations: {
        activity: true,
        supplier: true,
        items: true,
      },
      order: { items: { ticket_ref_no: 'ASC' } } as FindOptionsOrder<ActivityTicketBatchEntity>,
    });
  }

  async findActiveBatchesForActivity(activityId: string): Promise<ActivityTicketBatchEntity[]> {
    const tenantId = this.getTenantId();
    return this.repo.find({
      where: {
        activity_id: activityId,
        tenant_id: tenantId,
        status: TicketBatchStatus.ACTIVE,
        is_deleted: false,
      },
      relations: {
        supplier: true,
      },
      order: { valid_from: 'ASC' } as FindOptionsOrder<ActivityTicketBatchEntity>,
    });
  }

  /**
   * Returns active batches linked to a specific booking reference / booking ID.
   * Used by Movement Dashboard ticket assignment to show only relevant batches.
   */
  async findBatchesForBooking(
    bookingId: string,
    activityId?: string,
  ): Promise<ActivityTicketBatchEntity[]> {
    const tenantId = this.getTenantId();
    const qb = this.repo
      .createQueryBuilder('b')
      .where('b.tenant_id = :tenantId', { tenantId })
      .andWhere('b.is_deleted = false')
      // booking_reference_no stores comma-separated UUIDs; match if any element equals bookingId
      .andWhere(`:bookingId = ANY(string_to_array(b.booking_reference_no, ','))`, { bookingId })
      .andWhere('b.available_qty > 0');
    if (activityId) {
      qb.andWhere('b.activity_id = :activityId', { activityId });
    }
    return qb.orderBy('b.created_at', 'DESC').getMany();
  }
}
