/**
 * TypeORM InvitationToken Repository
 *
 * Implements InvitationTokenRepository port using TypeORM
 */

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, LessThan } from 'typeorm';
import { InvitationTokenRepository } from '@domain/ports/out/invitation-token.repository';
import { InvitationToken } from '@domain/entities/invitation-token.entity';
import { InvitationTokenOrmEntity } from '../entities/invitation-token.orm-entity';
import { InvitationTokenOrmMapper } from '../mappers/invitation-token-orm.mapper';

@Injectable()
export class TypeOrmInvitationTokenRepository implements InvitationTokenRepository {
  constructor(
    @InjectRepository(InvitationTokenOrmEntity)
    private readonly repository: Repository<InvitationTokenOrmEntity>
  ) {}

  async save(invitationToken: InvitationToken): Promise<InvitationToken> {
    const ormEntity = InvitationTokenOrmMapper.toOrm(invitationToken);
    const saved = await this.repository.save(ormEntity);
    return InvitationTokenOrmMapper.toDomain(saved);
  }

  async findByToken(token: string): Promise<InvitationToken | null> {
    const ormEntity = await this.repository.findOne({
      where: { token },
    });

    return ormEntity ? InvitationTokenOrmMapper.toDomain(ormEntity) : null;
  }

  async findActiveByEmail(email: string): Promise<InvitationToken | null> {
    const ormEntity = await this.repository.findOne({
      where: {
        email,
        isUsed: false,
      },
      order: {
        createdAt: 'DESC',
      },
    });

    if (!ormEntity) {
      return null;
    }

    const domain = InvitationTokenOrmMapper.toDomain(ormEntity);

    // Check if expired
    if (domain.isExpired()) {
      return null;
    }

    return domain;
  }

  async findByOrganization(organizationId: string): Promise<InvitationToken[]> {
    const ormEntities = await this.repository.find({
      where: { organizationId },
      order: {
        createdAt: 'DESC',
      },
    });

    return ormEntities.map(entity => InvitationTokenOrmMapper.toDomain(entity));
  }

  async deleteExpired(): Promise<number> {
    const result = await this.repository.delete({
      expiresAt: LessThan(new Date()),
      isUsed: false,
    });

    return result.affected || 0;
  }

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

  async update(invitationToken: InvitationToken): Promise<InvitationToken> {
    const ormEntity = InvitationTokenOrmMapper.toOrm(invitationToken);
    const updated = await this.repository.save(ormEntity);
    return InvitationTokenOrmMapper.toDomain(updated);
  }
}
