import { ExternalGameRatingProfile } from '@core/identity/domain/entities/ExternalGameRatingProfile';
import { ExternalGameRatingRepository, PaginatedQueryOptions, PaginatedResult } from '@core/identity/domain/repositories/ExternalGameRatingRepository';
import { Repository } from 'typeorm';
import { ExternalGameRatingProfileOrmEntity } from '../entities/ExternalGameRatingProfileOrmEntity';
import { ExternalGameRatingProfileOrmMapper } from '../mappers/ExternalGameRatingProfileOrmMapper';

/**
 * TypeORM Implementation: IExternalGameRatingRepository
 * 
 * Repository for external game rating profiles using TypeORM.
 * Implements store/display operations only, no compute.
 */
export class TypeOrmExternalGameRatingRepository implements ExternalGameRatingRepository {
  constructor(
    private readonly repository: Repository<ExternalGameRatingProfileOrmEntity>
  ) {}

  async findByUserIdAndGameKey(
    userId: string,
    gameKey: string
  ): Promise<ExternalGameRatingProfile | null> {
    const entity = await this.repository.findOne({
      where: { userId, gameKey },
    });

    if (!entity) {
      return null;
    }

    return ExternalGameRatingProfileOrmMapper.toDomain(entity);
  }

  async findByUserId(userId: string): Promise<ExternalGameRatingProfile[]> {
    const entities = await this.repository.find({
      where: { userId },
      order: { updatedAt: 'DESC' },
    });

    return entities.map(entity => ExternalGameRatingProfileOrmMapper.toDomain(entity));
  }

  async findByGameKey(gameKey: string): Promise<ExternalGameRatingProfile[]> {
    const entities = await this.repository.find({
      where: { gameKey },
      order: { updatedAt: 'DESC' },
    });

    return entities.map(entity => ExternalGameRatingProfileOrmMapper.toDomain(entity));
  }

  async save(profile: ExternalGameRatingProfile): Promise<ExternalGameRatingProfile> {
    const existing = await this.repository.findOne({
      where: {
        userId: profile.userId.toString(),
        gameKey: profile.gameKey.toString(),
      },
    });

    let entity: ExternalGameRatingProfileOrmEntity;

    if (existing) {
      // Update existing
      entity = ExternalGameRatingProfileOrmMapper.updateOrmEntity(existing, profile);
    } else {
      // Create new
      entity = ExternalGameRatingProfileOrmMapper.toOrmEntity(profile);
    }

    const saved = await this.repository.save(entity);
    return ExternalGameRatingProfileOrmMapper.toDomain(saved);
  }

  async saveMany(profiles: ExternalGameRatingProfile[]): Promise<ExternalGameRatingProfile[]> {
    const results: ExternalGameRatingProfile[] = [];

    for (const profile of profiles) {
      const saved = await this.save(profile);
      results.push(saved);
    }

    return results;
  }

  async delete(userId: string, gameKey: string): Promise<boolean> {
    const result = await this.repository.delete({ userId, gameKey });
    return (result.affected ?? 0) > 0;
  }

  async exists(userId: string, gameKey: string): Promise<boolean> {
    const count = await this.repository.count({
      where: { userId, gameKey },
    });
    return count > 0;
  }

  async findProfilesPaginated(userId: string, options?: PaginatedQueryOptions): Promise<PaginatedResult<ExternalGameRatingProfile>> {
    const query = this.repository.createQueryBuilder('profile')
      .where('profile.userId = :userId', { userId });

    // Apply filters
    if (options?.filter) {
      const filter = options.filter;
      
      if (filter.gameKeys) {
        query.andWhere('profile.gameKey IN (:...gameKeys)', { gameKeys: filter.gameKeys });
      }
      
      if (filter.sources) {
        query.andWhere('profile.provenanceSource IN (:...sources)', { sources: filter.sources });
      }
      
      if (filter.verified !== undefined) {
        query.andWhere('profile.provenanceVerified = :verified', { verified: filter.verified });
      }
      
      if (filter.lastSyncedAfter) {
        query.andWhere('profile.provenanceLastSyncedAt >= :lastSyncedAfter', { lastSyncedAfter: filter.lastSyncedAfter });
      }
    }

    // Get total count
    const total = await query.getCount();

    // Apply pagination
    const limit = options?.limit ?? 10;
    const offset = options?.offset ?? 0;
    
    query
      .orderBy('profile.updatedAt', 'DESC')
      .limit(limit)
      .offset(offset);

    const entities = await query.getMany();
    const items = entities.map(entity => ExternalGameRatingProfileOrmMapper.toDomain(entity));

    const hasMore = offset + limit < total;
    const nextOffset = hasMore ? offset + limit : undefined;

    const result: PaginatedResult<ExternalGameRatingProfile> = {
      items,
      total,
      limit,
      offset,
      hasMore
    };
    
    if (nextOffset !== undefined) {
      result.nextOffset = nextOffset;
    }

    return result;
  }
}
