/**
 * CapacitacionService - Servicio para catálogo de capacitaciones HSE
 *
 * Gestión de capacitaciones con CRUD y filtros.
 *
 * @module HSE
 */

import { Repository, FindOptionsWhere } from 'typeorm';
import { Capacitacion, TipoCapacitacion } from '../entities/capacitacion.entity';
import { ServiceContext, PaginatedResult } from '../../../shared/services/base.service';

export interface CreateCapacitacionDto {
  codigo: string;
  nombre: string;
  descripcion?: string;
  tipo: TipoCapacitacion;
  duracionHoras?: number;
  vigenciaMeses?: number;
  requiereEvaluacion?: boolean;
  calificacionMinima?: number;
}

export interface UpdateCapacitacionDto {
  nombre?: string;
  descripcion?: string;
  tipo?: TipoCapacitacion;
  duracionHoras?: number;
  vigenciaMeses?: number;
  requiereEvaluacion?: boolean;
  calificacionMinima?: number;
  activo?: boolean;
}

export interface CapacitacionFilters {
  tipo?: TipoCapacitacion;
  activo?: boolean;
  search?: string;
}

export class CapacitacionService {
  constructor(private readonly repository: Repository<Capacitacion>) {}

  async findAll(
    ctx: ServiceContext,
    filters: CapacitacionFilters = {},
    page: number = 1,
    limit: number = 20
  ): Promise<PaginatedResult<Capacitacion>> {
    const skip = (page - 1) * limit;

    const queryBuilder = this.repository
      .createQueryBuilder('capacitacion')
      .where('capacitacion.tenant_id = :tenantId', { tenantId: ctx.tenantId });

    if (filters.tipo) {
      queryBuilder.andWhere('capacitacion.tipo = :tipo', { tipo: filters.tipo });
    }

    if (filters.activo !== undefined) {
      queryBuilder.andWhere('capacitacion.activo = :activo', { activo: filters.activo });
    }

    if (filters.search) {
      queryBuilder.andWhere(
        '(capacitacion.codigo ILIKE :search OR capacitacion.nombre ILIKE :search)',
        { search: `%${filters.search}%` }
      );
    }

    queryBuilder
      .orderBy('capacitacion.nombre', 'ASC')
      .skip(skip)
      .take(limit);

    const [data, total] = await queryBuilder.getManyAndCount();

    return {
      data,
      total,
      page,
      limit,
      totalPages: Math.ceil(total / limit),
    };
  }

  async findById(ctx: ServiceContext, id: string): Promise<Capacitacion | null> {
    return this.repository.findOne({
      where: {
        id,
        tenantId: ctx.tenantId,
      } as FindOptionsWhere<Capacitacion>,
    });
  }

  async findByCodigo(ctx: ServiceContext, codigo: string): Promise<Capacitacion | null> {
    return this.repository.findOne({
      where: {
        codigo,
        tenantId: ctx.tenantId,
      } as FindOptionsWhere<Capacitacion>,
    });
  }

  async create(ctx: ServiceContext, dto: CreateCapacitacionDto): Promise<Capacitacion> {
    const existing = await this.findByCodigo(ctx, dto.codigo);
    if (existing) {
      throw new Error(`Capacitacion with codigo ${dto.codigo} already exists`);
    }

    const capacitacion = this.repository.create({
      tenantId: ctx.tenantId,
      codigo: dto.codigo,
      nombre: dto.nombre,
      descripcion: dto.descripcion,
      tipo: dto.tipo,
      duracionHoras: dto.duracionHoras || 1,
      vigenciaMeses: dto.vigenciaMeses,
      requiereEvaluacion: dto.requiereEvaluacion || false,
      calificacionMinima: dto.calificacionMinima,
      activo: true,
    });

    return this.repository.save(capacitacion);
  }

  async update(ctx: ServiceContext, id: string, dto: UpdateCapacitacionDto): Promise<Capacitacion | null> {
    const existing = await this.findById(ctx, id);
    if (!existing) {
      return null;
    }

    const updated = this.repository.merge(existing, dto);
    return this.repository.save(updated);
  }

  async toggleActive(ctx: ServiceContext, id: string): Promise<Capacitacion | null> {
    const existing = await this.findById(ctx, id);
    if (!existing) {
      return null;
    }

    existing.activo = !existing.activo;
    return this.repository.save(existing);
  }

  async getByTipo(ctx: ServiceContext, tipo: TipoCapacitacion): Promise<Capacitacion[]> {
    return this.repository.find({
      where: {
        tenantId: ctx.tenantId,
        tipo,
        activo: true,
      } as FindOptionsWhere<Capacitacion>,
      order: { nombre: 'ASC' },
    });
  }
}
