/**
 * TypeORM License Repository
 *
 * Implements LicenseRepository interface using TypeORM
 */

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { License } from '@domain/entities/license.entity';
import { LicenseRepository } from '@domain/ports/out/license.repository';
import { LicenseOrmEntity } from '../entities/license.orm-entity';
import { LicenseOrmMapper } from '../mappers/license-orm.mapper';

@Injectable()
export class TypeOrmLicenseRepository implements LicenseRepository {
  constructor(
    @InjectRepository(LicenseOrmEntity)
    private readonly repository: Repository<LicenseOrmEntity>
  ) {}

  async save(license: License): Promise<License> {
    const orm = LicenseOrmMapper.toOrm(license);
    const saved = await this.repository.save(orm);
    return LicenseOrmMapper.toDomain(saved);
  }

  async findById(id: string): Promise<License | null> {
    const orm = await this.repository.findOne({ where: { id } });
    return orm ? LicenseOrmMapper.toDomain(orm) : null;
  }

  async findByUserId(userId: string): Promise<License | null> {
    const orm = await this.repository.findOne({ where: { userId } });
    return orm ? LicenseOrmMapper.toDomain(orm) : null;
  }

  async findBySubscriptionId(subscriptionId: string): Promise<License[]> {
    const orms = await this.repository.find({
      where: { subscriptionId },
      order: { assignedAt: 'DESC' },
    });
    return LicenseOrmMapper.toDomainMany(orms);
  }

  async findActiveBySubscriptionId(subscriptionId: string): Promise<License[]> {
    const orms = await this.repository.find({
      where: { subscriptionId, status: 'ACTIVE' },
      order: { assignedAt: 'DESC' },
    });
    return LicenseOrmMapper.toDomainMany(orms);
  }

  async countActiveBySubscriptionId(subscriptionId: string): Promise<number> {
    return this.repository.count({
      where: { subscriptionId, status: 'ACTIVE' },
    });
  }

  async countActiveBySubscriptionIdExcludingAdmins(subscriptionId: string): Promise<number> {
    const result = await this.repository
      .createQueryBuilder('license')
      .innerJoin('license.user', 'user')
      .where('license.subscriptionId = :subscriptionId', { subscriptionId })
      .andWhere('license.status = :status', { status: 'ACTIVE' })
      .andWhere('user.role != :adminRole', { adminRole: 'ADMIN' })
      .getCount();
    return result;
  }

  async findActiveBySubscriptionIdExcludingAdmins(subscriptionId: string): Promise<License[]> {
    const orms = await this.repository
      .createQueryBuilder('license')
      .innerJoin('license.user', 'user')
      .where('license.subscriptionId = :subscriptionId', { subscriptionId })
      .andWhere('license.status = :status', { status: 'ACTIVE' })
      .andWhere('user.role != :adminRole', { adminRole: 'ADMIN' })
      .orderBy('license.assignedAt', 'DESC')
      .getMany();
    return LicenseOrmMapper.toDomainMany(orms);
  }

  async delete(id: string): Promise<void> {
    await this.repository.delete({ id });
  }

  async deleteBySubscriptionId(subscriptionId: string): Promise<void> {
    await this.repository.delete({ subscriptionId });
  }
}
