import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { BaseTenantRepository, TenantContextService } from '@iconsulting/shared';
import { ConversationORM } from '../../../infrastructure/database/postgres/entities/conversation.orm';
import { IConversationRepository } from '../../../domain/repositories/conversation.repository.interface';
import {
  ConversationEntity,
  ConversationStatusType,
} from '../../../domain/entities/conversation.entity';

@Injectable()
export class ConversationPostgresRepository
  extends BaseTenantRepository<ConversationEntity, ConversationORM>
  implements IConversationRepository
{
  constructor(
    @InjectRepository(ConversationORM) repo: Repository<ConversationORM>,
    tenantContext: TenantContextService,
  ) {
    super(repo, tenantContext);
  }

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

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

  async findByUserId(
    userId: string,
    options?: { status?: ConversationStatusType; limit?: number },
  ): Promise<ConversationEntity[]> {
    const queryBuilder = this.createTenantQueryBuilder('conversation')
      .andWhere('conversation.user_id = :userId', { userId })
      .andWhere('conversation.status != :deletedStatus', { deletedStatus: 'DELETED' });

    if (options?.status) {
      queryBuilder.andWhere('conversation.status = :status', { status: options.status });
    }

    queryBuilder.orderBy('conversation.created_at', 'DESC');

    if (options?.limit) {
      queryBuilder.limit(options.limit);
    }

    const orms = await queryBuilder.getMany();
    return orms.map((orm) => this.toEntity(orm));
  }

  async findForEvolution(options: {
    status?: ConversationStatusType;
    hoursBack?: number;
    minMessageCount?: number;
  }): Promise<ConversationEntity[]> {
    const queryBuilder = this.createTenantQueryBuilder('conversation')
      .andWhere('conversation.status != :deletedStatus', { deletedStatus: 'DELETED' });

    if (options.status) {
      queryBuilder.andWhere('conversation.status = :status', { status: options.status });
    }

    if (options.hoursBack) {
      const cutoffDate = new Date();
      cutoffDate.setHours(cutoffDate.getHours() - options.hoursBack);
      queryBuilder.andWhere('conversation.created_at >= :cutoffDate', { cutoffDate });
    }

    if (options.minMessageCount) {
      queryBuilder.andWhere('conversation.message_count >= :minCount', {
        minCount: options.minMessageCount,
      });
    }

    const orms = await queryBuilder.getMany();
    return orms.map((orm) => this.toEntity(orm));
  }

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

  async count(options?: { status?: ConversationStatusType; daysBack?: number }): Promise<number> {
    const queryBuilder = this.createTenantQueryBuilder('conversation');

    if (options?.status) {
      queryBuilder.andWhere('conversation.status = :status', { status: options.status });
    }

    if (options?.daysBack) {
      const cutoffDate = new Date();
      cutoffDate.setDate(cutoffDate.getDate() - options.daysBack);
      queryBuilder.andWhere('conversation.created_at >= :cutoffDate', { cutoffDate });
    }

    return queryBuilder.getCount();
  }

  private toORM(entity: ConversationEntity): ConversationORM {
    const orm = new ConversationORM();
    orm.id = entity.id;
    orm.tenantId = this.getTenantId();
    orm.userId = entity.userId;
    orm.status = entity.status;
    orm.title = entity.title;
    orm.summary = entity.summary;
    orm.category = entity.category;
    orm.messageCount = entity.messageCount;
    orm.userMessageCount = entity.userMessageCount;
    orm.assistantMessageCount = entity.assistantMessageCount;
    orm.totalInputTokens = entity.totalInputTokens;
    orm.totalOutputTokens = entity.totalOutputTokens;
    orm.rating = entity.rating;
    orm.feedback = entity.feedback;
    orm.hasConverted = entity.hasConverted;
    orm.consultingStage = entity.consultingStage;
    orm.consultingState = entity.consultingState;
    orm.collectedInfo = entity.collectedInfo;
    orm.recommendedPrograms = entity.recommendedPrograms;
    orm.conversionPath = entity.conversionPath;
    orm.deviceInfo = entity.deviceInfo;
    orm.createdAt = entity.createdAt;
    orm.updatedAt = entity.updatedAt;
    orm.endedAt = entity.endedAt;
    return orm;
  }

  private toEntity(orm: ConversationORM): ConversationEntity {
    return ConversationEntity.fromPersistence({
      id: orm.id,
      userId: orm.userId,
      status: orm.status,
      title: orm.title,
      summary: orm.summary,
      category: orm.category,
      messageCount: orm.messageCount,
      userMessageCount: orm.userMessageCount,
      assistantMessageCount: orm.assistantMessageCount,
      totalInputTokens: orm.totalInputTokens,
      totalOutputTokens: orm.totalOutputTokens,
      rating: orm.rating,
      feedback: orm.feedback,
      hasConverted: orm.hasConverted,
      consultingStage: orm.consultingStage,
      consultingState: orm.consultingState,
      collectedInfo: orm.collectedInfo,
      recommendedPrograms: orm.recommendedPrograms,
      conversionPath: orm.conversionPath,
      deviceInfo: orm.deviceInfo,
      createdAt: orm.createdAt,
      updatedAt: orm.updatedAt,
      endedAt: orm.endedAt,
    });
  }
}
