import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { MaintenanceRequest } from '../entities/maintenance-request.entity';
import { Machine } from '../entities/machine.entity';
import { ProductionLine } from '../entities/production-line.entity';
import { CreateMaintenanceRequestDto } from '../dto/create-maintenance-request.dto';
import { UpdateMaintenanceRequestDto } from '../dto/update-maintenance-request.dto';

@Injectable()
export class MaintenanceService {
  constructor(
    @InjectRepository(MaintenanceRequest)
    private maintenanceRequestRepository: Repository<MaintenanceRequest>,
    @InjectRepository(Machine)
    private machineRepository: Repository<Machine>,
    @InjectRepository(ProductionLine)
    private productionLineRepository: Repository<ProductionLine>,
  ) {}

  async createMaintenanceRequest(
    createDto: CreateMaintenanceRequestDto,
  ): Promise<MaintenanceRequest> {
    const machine = await this.machineRepository.findOne({
      where: { id: createDto.machineId },
      relations: ['productionLine'],
    });

    if (!machine) {
      throw new Error('Machine not found');
    }

    // Handle assignedTechnician as string (ID) or object
    let assignedTechnician = undefined;
    if (createDto.assignedTechnician) {
      assignedTechnician = { id: createDto.assignedTechnician };
    }

    const maintenanceRequest = this.maintenanceRequestRepository.create({
      ...createDto,
      assignedTechnician,
      status: 'pending' as any,
      createdAt: new Date(),
    });

    // Update machine status to maintenance
    machine.status = 'maintenance';
    await this.machineRepository.save(machine);

    return this.maintenanceRequestRepository.save(maintenanceRequest);
  }

  async getMaintenanceRequests(
    status?: string,
    productionLineId?: string,
  ): Promise<MaintenanceRequest[]> {
    const query = this.maintenanceRequestRepository
      .createQueryBuilder('request')
      .leftJoinAndSelect('request.machine', 'machine')
      .leftJoinAndSelect('machine.productionLine', 'line')
      .orderBy('request.createdAt', 'DESC');

    if (status) {
      query.where('request.status = :status', { status });
    }

    if (productionLineId) {
      query.andWhere('line.id = :productionLineId', { productionLineId });
    }

    return query.getMany();
  }

  async updateMaintenanceRequest(
    id: string,
    updateDto: UpdateMaintenanceRequestDto,
  ): Promise<MaintenanceRequest> {
    const maintenanceRequest = await this.maintenanceRequestRepository.findOne({
      where: { id },
      relations: ['machine'],
    });

    if (!maintenanceRequest) {
      throw new Error('Maintenance request not found');
    }

    // Update machine status if maintenance is complete
    if ((updateDto as any).status === 'completed') {
      maintenanceRequest.machine.status = 'active';
      await this.machineRepository.save(maintenanceRequest.machine);
    }

    // Handle assignedTechnician as string (ID) or object
    if (updateDto.assignedTechnician) {
      maintenanceRequest.assignedTechnician = { id: updateDto.assignedTechnician } as any;
    }

    Object.assign(maintenanceRequest, updateDto);
    return this.maintenanceRequestRepository.save(maintenanceRequest);
  }

  async getMaintenanceHistory(
    machineId: string,
    startDate?: Date,
    endDate?: Date,
  ): Promise<MaintenanceRequest[]> {
    const query = this.maintenanceRequestRepository
      .createQueryBuilder('request')
      .where('request.machineId = :machineId', { machineId });

    if (startDate) {
      query.andWhere('request.createdAt >= :startDate', { startDate });
    }

    if (endDate) {
      query.andWhere('request.createdAt <= :endDate', { endDate });
    }

    return query.getMany();
  }

  async getMachineAvailability(
    machineId: string,
    startDate: Date,
    endDate: Date,
  ): Promise<number> {
    const totalHours = (endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60);

    const maintenanceRequests = await this.maintenanceRequestRepository
      .createQueryBuilder('request')
      .where('request.machineId = :machineId', { machineId })
      .andWhere('request.createdAt BETWEEN :start AND :end', {
        start: startDate,
        end: endDate,
      })
      .getMany();

    const downtimeHours = maintenanceRequests.reduce((sum, request) => {
      if (request.status === 'completed') {
        return sum + (request.completedDate!.getTime() - request.createdAt.getTime()) /
          (1000 * 60 * 60);
      }
      return sum;
    }, 0);

    return ((totalHours - downtimeHours) / totalHours) * 100;
  }

  // Additional methods for controller compatibility
  async findAll(query?: any): Promise<MaintenanceRequest[]> {
    return this.getMaintenanceRequests();
  }

  async findOne(id: string): Promise<MaintenanceRequest> {
    return this.maintenanceRequestRepository.findOne({
      where: { id },
      relations: ['machine', 'assignedTechnician'],
    });
  }

  async create(createDto: CreateMaintenanceRequestDto): Promise<MaintenanceRequest> {
    return this.createMaintenanceRequest(createDto);
  }

  async update(id: string, updateDto: UpdateMaintenanceRequestDto): Promise<MaintenanceRequest> {
    return this.updateMaintenanceRequest(id, updateDto);
  }

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

  async findByStatus(status: string): Promise<MaintenanceRequest[]> {
    return this.getMaintenanceRequests(status);
  }

  async findByPriority(priority: string): Promise<MaintenanceRequest[]> {
    return this.maintenanceRequestRepository.find({
      where: { priority: priority as any },
      relations: ['machine', 'assignedTechnician'],
    });
  }

  async findByMachine(machineId: string): Promise<MaintenanceRequest[]> {
    return this.maintenanceRequestRepository.find({
      where: { machineId },
      relations: ['machine', 'assignedTechnician'],
    });
  }

  async getSchedules(): Promise<any[]> {
    return this.maintenanceRequestRepository.find({
      where: { status: 'pending' as any },
      relations: ['machine', 'assignedTechnician'],
    });
  }

  async getHistory(): Promise<MaintenanceRequest[]> {
    return this.maintenanceRequestRepository.find({
      where: { status: 'completed' as any },
      relations: ['machine', 'assignedTechnician'],
      order: { completedDate: 'DESC' },
    });
  }
}
