import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, IsNull } from 'typeorm';
import { EvaluationRuleORM } from '../entities/evaluation-rule.orm';
import {
  IEvaluationRuleRepository,
} from '../../../../domain/repositories/evaluation-rule.repository.interface';
import {
  EvaluationRuleEntity,
  EvaluationRuleTypeValue,
  EvaluationFailureActionValue,
} from '../../../../domain/entities/evaluation-rule.entity';

@Injectable()
export class EvaluationRulePostgresRepository implements IEvaluationRuleRepository {
  constructor(
    @InjectRepository(EvaluationRuleORM)
    private readonly repo: Repository<EvaluationRuleORM>,
  ) {}

  async findByTenantAndStage(
    tenantId: string | null,
    stage: string,
  ): Promise<EvaluationRuleEntity[]> {
    const orms = await this.repo
      .createQueryBuilder('r')
      .where('(r.tenant_id = :tenantId OR r.tenant_id IS NULL)', { tenantId })
      .andWhere('(r.stage = :stage OR r.stage = :wildcard)', { stage, wildcard: '*' })
      .andWhere('r.enabled = true')
      .orderBy('r.priority', 'ASC')
      .getMany();

    return orms.map(orm => this.toEntity(orm));
  }

  async findAllByTenant(tenantId: string | null): Promise<EvaluationRuleEntity[]> {
    const orms = await this.repo.find({
      where: { tenantId: tenantId ?? IsNull() },
      order: { stage: 'ASC', priority: 'ASC' },
    });
    return orms.map(orm => this.toEntity(orm));
  }

  async findById(id: string): Promise<EvaluationRuleEntity | null> {
    const orm = await this.repo.findOne({ where: { id } });
    return orm ? this.toEntity(orm) : null;
  }

  async save(rule: EvaluationRuleEntity): Promise<EvaluationRuleEntity> {
    const orm = this.toORM(rule);
    const saved = await this.repo.save(orm);
    return this.toEntity(saved);
  }

  async update(rule: EvaluationRuleEntity): Promise<EvaluationRuleEntity> {
    const orm = this.toORM(rule);
    const saved = await this.repo.save(orm);
    return this.toEntity(saved);
  }

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

  private toEntity(orm: EvaluationRuleORM): EvaluationRuleEntity {
    return EvaluationRuleEntity.fromPersistence({
      id: orm.id,
      tenantId: orm.tenantId,
      stage: orm.stage,
      ruleType: orm.ruleType as EvaluationRuleTypeValue,
      name: orm.name,
      description: orm.description,
      config: orm.config,
      enabled: orm.enabled,
      priority: orm.priority,
      failureAction: orm.failureAction as EvaluationFailureActionValue,
      createdBy: orm.createdBy,
      updatedBy: orm.updatedBy,
      createdAt: orm.createdAt,
      updatedAt: orm.updatedAt,
    });
  }

  private toORM(entity: EvaluationRuleEntity): EvaluationRuleORM {
    const orm = new EvaluationRuleORM();
    orm.id = entity.id;
    orm.tenantId = entity.tenantId;
    orm.stage = entity.stage;
    orm.ruleType = entity.ruleType;
    orm.name = entity.name;
    orm.description = entity.description;
    orm.config = entity.config;
    orm.enabled = entity.enabled;
    orm.priority = entity.priority;
    orm.failureAction = entity.failureAction;
    orm.createdBy = entity.createdBy;
    orm.updatedBy = entity.updatedBy;
    return orm;
  }
}
