/**
 * InstructorService - Servicio para gestión de instructores HSE
 *
 * RF-MAA017-002: Control de Capacitaciones - Instructores
 *
 * @module HSE
 */

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

export interface CreateInstructorDto {
  nombre: string;
  registroStps?: string;
  especialidades?: string;
  esInterno?: boolean;
  employeeId?: string;
  contactoTelefono?: string;
  contactoEmail?: string;
}

export interface UpdateInstructorDto {
  nombre?: string;
  registroStps?: string;
  especialidades?: string;
  esInterno?: boolean;
  employeeId?: string;
  contactoTelefono?: string;
  contactoEmail?: string;
  activo?: boolean;
}

export interface InstructorFilters {
  esInterno?: boolean;
  activo?: boolean;
  search?: string;
}

export class InstructorService {
  constructor(private readonly repository: Repository<Instructor>) {}

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

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

    if (filters.esInterno !== undefined) {
      queryBuilder.andWhere('instructor.es_interno = :esInterno', { esInterno: filters.esInterno });
    }

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

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

    queryBuilder
      .orderBy('instructor.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<Instructor | null> {
    return this.repository.findOne({
      where: {
        id,
        tenantId: ctx.tenantId,
      } as FindOptionsWhere<Instructor>,
      relations: ['employee'],
    });
  }

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

  async create(ctx: ServiceContext, dto: CreateInstructorDto): Promise<Instructor> {
    if (dto.registroStps) {
      const existing = await this.findByRegistroStps(ctx, dto.registroStps);
      if (existing) {
        throw new Error(`Instructor with registro STPS ${dto.registroStps} already exists`);
      }
    }

    const instructor = this.repository.create({
      tenantId: ctx.tenantId,
      nombre: dto.nombre,
      registroStps: dto.registroStps,
      especialidades: dto.especialidades,
      esInterno: dto.esInterno || false,
      employeeId: dto.employeeId,
      contactoTelefono: dto.contactoTelefono,
      contactoEmail: dto.contactoEmail,
      activo: true,
    });

    return this.repository.save(instructor);
  }

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

    if (dto.registroStps && dto.registroStps !== existing.registroStps) {
      const duplicate = await this.findByRegistroStps(ctx, dto.registroStps);
      if (duplicate) {
        throw new Error(`Instructor with registro STPS ${dto.registroStps} already exists`);
      }
    }

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

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

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

  async getInstructoresActivos(ctx: ServiceContext): Promise<Instructor[]> {
    return this.repository.find({
      where: {
        tenantId: ctx.tenantId,
        activo: true,
      } as FindOptionsWhere<Instructor>,
      relations: ['employee'],
      order: { nombre: 'ASC' },
    });
  }

  async getInstructoresInternos(ctx: ServiceContext): Promise<Instructor[]> {
    return this.repository.find({
      where: {
        tenantId: ctx.tenantId,
        esInterno: true,
        activo: true,
      } as FindOptionsWhere<Instructor>,
      relations: ['employee'],
      order: { nombre: 'ASC' },
    });
  }

  async getInstructoresExternos(ctx: ServiceContext): Promise<Instructor[]> {
    return this.repository.find({
      where: {
        tenantId: ctx.tenantId,
        esInterno: false,
        activo: true,
      } as FindOptionsWhere<Instructor>,
      order: { nombre: 'ASC' },
    });
  }
}
