import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { BaseTenantRepository, TenantContextService } from '@iconsulting/shared';
import { IFileRepository } from '../../../domain/repositories/file.repository.interface';
import { FileEntity, FileStatus } from '../../../domain/entities/file.entity';
import { FileORM } from '../../../infrastructure/database/postgres/entities/file.orm';

@Injectable()
export class FilePostgresRepository
  extends BaseTenantRepository<FileEntity, FileORM>
  implements IFileRepository
{
  constructor(
    @InjectRepository(FileORM) repo: Repository<FileORM>,
    tenantContext: TenantContextService,
  ) {
    super(repo, tenantContext);
  }

  async save(file: FileEntity): Promise<FileEntity> {
    const orm = this.toORM(file);
    orm.tenantId = this.getTenantId();
    const saved = await this.repo.save(orm);
    return this.toEntity(saved);
  }

  async findById(id: string): Promise<FileEntity | null> {
    const orm = await this.findOneWithTenant({ id } as any);
    return orm ? this.toEntity(orm) : null;
  }

  async findByIdAndUser(id: string, userId: string): Promise<FileEntity | null> {
    const orm = await this.findOneWithTenant({ id, userId } as any);
    return orm ? this.toEntity(orm) : null;
  }

  async findByIdAndUserAndStatus(
    id: string,
    userId: string,
    status: FileStatus,
  ): Promise<FileEntity | null> {
    const orm = await this.findOneWithTenant({ id, userId, status } as any);
    return orm ? this.toEntity(orm) : null;
  }

  async findByUserAndStatus(
    userId: string,
    status: FileStatus,
    conversationId?: string,
  ): Promise<FileEntity[]> {
    const queryBuilder = this.createTenantQueryBuilder('file')
      .andWhere('file.user_id = :userId', { userId })
      .andWhere('file.status = :status', { status });

    if (conversationId) {
      queryBuilder.andWhere('file.conversation_id = :conversationId', { conversationId });
    }

    const orms = await queryBuilder.orderBy('file.created_at', 'DESC').getMany();
    return orms.map((orm) => this.toEntity(orm));
  }

  async update(file: FileEntity): Promise<FileEntity> {
    const orm = this.toORM(file);
    orm.tenantId = this.getTenantId();
    const saved = await this.repo.save(orm);
    return this.toEntity(saved);
  }

  private toORM(entity: FileEntity): FileORM {
    const orm = new FileORM();
    orm.id = entity.id;
    orm.tenantId = this.getTenantId();
    orm.userId = entity.userId;
    orm.conversationId = entity.conversationId;
    orm.originalName = entity.originalName;
    orm.storagePath = entity.storagePath;
    orm.mimeType = entity.mimeType;
    orm.type = entity.type;
    orm.size = entity.size;
    orm.status = entity.status;
    orm.thumbnailPath = entity.thumbnailPath;
    orm.metadata = entity.metadata;
    orm.extractedText = entity.extractedText;
    orm.errorMessage = entity.errorMessage;
    orm.createdAt = entity.createdAt;
    orm.updatedAt = entity.updatedAt;
    orm.deletedAt = entity.deletedAt;
    return orm;
  }

  private toEntity(orm: FileORM): FileEntity {
    return FileEntity.fromPersistence({
      id: orm.id,
      tenantId: orm.tenantId,
      userId: orm.userId,
      conversationId: orm.conversationId,
      originalName: orm.originalName,
      storagePath: orm.storagePath,
      mimeType: orm.mimeType,
      type: orm.type,
      size: Number(orm.size),
      status: orm.status,
      thumbnailPath: orm.thumbnailPath,
      metadata: orm.metadata,
      extractedText: orm.extractedText,
      errorMessage: orm.errorMessage,
      createdAt: orm.createdAt,
      updatedAt: orm.updatedAt,
      deletedAt: orm.deletedAt,
    });
  }
}
