import {
  BadRequestException,
  Injectable,
  NotFoundException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Queue } from './entities/queue.entity';
import { CreateQueueDto } from './dto/create-queue.dto';
import { UpdateQueueDto } from './dto/update-queue.dto';
import { Machine } from '@/machines/entities/machine.entity';
import { Page } from '@/pages/entities/page.entity';
import { Order } from '@/orders/entities/order.entity';
import { Employee } from '@/employees/entities/employee.entity';

@Injectable()
export class QueuesService {
  constructor(
    @InjectRepository(Queue)
    private readonly queueRepository: Repository<Queue>,

    @InjectRepository(Machine)
    private readonly machineRepository: Repository<Machine>,

    @InjectRepository(Page)
    private readonly pageRepository: Repository<Page>,

    @InjectRepository(Order)
    private readonly orderRepository: Repository<Order>,

    @InjectRepository(Employee)
    private readonly employeeRepository: Repository<Employee>,
  ) {}

  async create(createQueueDto: CreateQueueDto) {
    const { MachineID, PageID, OrderID, EmployeeIds, ...queueData } =
      createQueueDto;

    // console.log('📌 Received CreateQueueDto:', createQueueDto);

    // 🔍 Fetch related entities
    const machine = await this.machineRepository.findOne({
      where: { MachineID },
    });
    if (!machine)
      throw new NotFoundException(`Machine with ID ${MachineID} not found`);

    const page = await this.pageRepository.findOne({ where: { PageID } });
    if (!page) throw new NotFoundException(`Page with ID ${PageID} not found`);

    const order = await this.orderRepository.findOne({ where: { OrderID } });
    if (!order)
      throw new NotFoundException(`Order with ID ${OrderID} not found`);

    const employees = await this.employeeRepository.findByIds(EmployeeIds);
    if (employees.length !== EmployeeIds.length) {
      throw new NotFoundException(`One or more employees not found`);
    }

    // console.log('✅ Related Entities Fetched:');
    // console.log('   - Machine:', machine);
    // console.log('   - Page:', page);
    // console.log('   - Order:', order);
    // console.log('   - Employees:', employees);

    // ✅ Create Queue entity and save to DB
    const newQueue = this.queueRepository.create({
      ...queueData,
      machine,
      page,
      order,
      employees,
    });

    // console.log('🛠️ Preparing to save new Queue:', newQueue);

    const savedQueue = await this.queueRepository.save(newQueue);

    // console.log('✅ Queue saved successfully:', savedQueue);

    // ✅ Return the response with full details
    return {
      message: 'Queue created successfully',
      queue: savedQueue,
    };
  }

  async createMultiple(createQueueDtos: CreateQueueDto[]) {
    const newQueues = [];

    if (!Array.isArray(createQueueDtos)) {
      throw new BadRequestException('Request body must be an array of queues');
    }
    for (const createQueueDto of createQueueDtos) {
      const { MachineID, PageID, OrderID, EmployeeIds, ...queueData } =
        createQueueDto;

      // console.log('👉 Raw EmployeeIds:', EmployeeIds);

      // ✅ ตรวจสอบว่า `EmployeeIds` เป็น Array ที่ไม่ว่าง
      if (!Array.isArray(EmployeeIds) || EmployeeIds.length === 0) {
        throw new BadRequestException(`EmployeeIds must be a non-empty array`);
      }

      // ✅ แปลงค่าให้เป็นตัวเลข และกรองค่าที่ไม่ถูกต้อง
      const validEmployeeIds = EmployeeIds.map((id) => Number(id)).filter(
        (id) => !isNaN(id) && id > 0,
      );

      // console.log('✅ Valid EmployeeIds:', validEmployeeIds);

      if (validEmployeeIds.length !== EmployeeIds.length) {
        throw new BadRequestException(
          `Invalid EmployeeIds provided: ${EmployeeIds}`,
        );
      }

      // ✅ ตรวจสอบและแปลง `MachineID`, `OrderID`, `PageID`
      const machineId = Number(MachineID);
      if (isNaN(machineId))
        throw new BadRequestException(`Invalid MachineID: ${MachineID}`);

      const orderId = Number(OrderID);
      if (isNaN(orderId))
        throw new BadRequestException(`Invalid OrderID: ${OrderID}`);

      let pageId: number | null = null;
      if (PageID !== null && PageID !== undefined) {
        pageId = Number(PageID);
        if (isNaN(pageId))
          throw new BadRequestException(`Invalid PageID: ${PageID}`);
      }

      // 🔍 ค้นหา Entity ที่เกี่ยวข้อง
      const machine = await this.machineRepository.findOne({
        where: { MachineID: machineId },
      });
      if (!machine)
        throw new NotFoundException(`Machine with ID ${machineId} not found`);

      const page =
        pageId !== null
          ? await this.pageRepository.findOne({ where: { PageID: pageId } })
          : null;
      if (pageId !== null && !page)
        throw new NotFoundException(`Page with ID ${pageId} not found`);

      const order = await this.orderRepository.findOne({
        where: { OrderID: orderId },
      });
      if (!order)
        throw new NotFoundException(`Order with ID ${orderId} not found`);

      // 🔍 ค้นหา Employees ที่มีอยู่ในฐานข้อมูล
      const employees =
        await this.employeeRepository.findByIds(validEmployeeIds);
      const foundIds = employees.map((e) => e.EmployeeID);
      const missingIds = validEmployeeIds.filter(
        (id) => !foundIds.includes(id),
      );

      if (missingIds.length > 0) {
        console.error(`❌ Missing EmployeeIDs: ${missingIds.join(', ')}`);
        throw new NotFoundException(
          `Employees not found: ${missingIds.join(', ')}`,
        );
      }

      // ✅ สร้าง Queue object
      const newQueue = this.queueRepository.create({
        ...queueData,
        machine,
        page,
        order,
        employees,
      });

      newQueues.push(newQueue);
    }

    // ✅ บันทึกทั้งหมดพร้อมกัน
    const savedQueues = await this.queueRepository.save(newQueues);

    return {
      message: `${savedQueues.length} queues created successfully`,
      queues: savedQueues,
    };
  }

  // ✅ Fetch all Queues with relationships
  async findAll() {
    return await this.queueRepository.find({
      relations: ['machine', 'page', 'order', 'employees'],
    });
  }

  // ✅ Fetch a single Queue by ID
  async findOne(id: number) {
    const queue = await this.queueRepository.findOne({
      where: { QueueID: id },
      relations: ['machine', 'page', 'order', 'employees'],
    });

    if (!queue) {
      throw new NotFoundException(`Queue with ID ${id} not found`);
    }

    return queue;
  }

  // ✅ Update Queue
  async update(id: number, updateQueueDto: UpdateQueueDto) {
    try {
      console.log('🔄 Updating Queue ID:', id, updateQueueDto);

      const {
        MachineID,
        PageID,
        OrderID,
        EmployeeIds,
        startTime,
        finishTime,
        ...queueData
      } = updateQueueDto;

      // 🔍 ค้นหา Queue ที่จะอัปเดต
      const existingQueue = await this.queueRepository.findOne({
        where: { QueueID: id },
        relations: ['machine', 'page', 'order', 'employees'],
      });

      if (!existingQueue) {
        throw new NotFoundException(`Queue with ID ${id} not found`);
      }

      // 🔍 Fetch entities if IDs are provided
      const machine = MachineID
        ? await this.machineRepository.findOne({ where: { MachineID } })
        : existingQueue.machine;

      if (MachineID && !machine)
        throw new NotFoundException(`Machine with ID ${MachineID} not found`);

      const page = PageID
        ? await this.pageRepository.findOne({ where: { PageID } })
        : existingQueue.page;

      if (PageID && !page)
        throw new NotFoundException(`Page with ID ${PageID} not found`);

      const order = OrderID
        ? await this.orderRepository.findOne({ where: { OrderID } })
        : existingQueue.order;

      if (OrderID && !order)
        throw new NotFoundException(`Order with ID ${OrderID} not found`);

      // 🔍 ค้นหา Employees และคำนวณการเชื่อมโยง
      let employees = existingQueue.employees;
      if (EmployeeIds) {
        const fetchedEmployees =
          await this.employeeRepository.findByIds(EmployeeIds);
        if (fetchedEmployees.length !== EmployeeIds.length) {
          throw new NotFoundException(`One or more employees not found`);
        }
        employees = fetchedEmployees;
      }

      // ✅ Convert timestamps from string to Date
      const updateData: Partial<Queue> = {
        ...queueData,
        machine,
        page,
        order,
        employees,
        startTime: startTime ? new Date(startTime) : existingQueue.startTime,
        finishTime: finishTime
          ? new Date(finishTime)
          : existingQueue.finishTime,
      };

      // ✅ ใช้ `save()` แทน `update()` เพื่อรองรับ Many-to-Many (employees)
      const updatedQueue = await this.queueRepository.save({
        ...existingQueue,
        ...updateData,
      });

      console.log('✅ Queue updated successfully:', updatedQueue);

      return updatedQueue;
    } catch (error) {
      console.error('❌ Error in updateQueue:', error);
      throw new Error('Database update failed');
    }
  }

  // ✅ Delete Queue
  async remove(id: number) {
    const queue = await this.queueRepository.findOne({
      where: { QueueID: id },
      relations: ['machine', 'page', 'order', 'employees'],
    });

    if (!queue) {
      throw new NotFoundException(`Queue with ID ${id} not found`);
    }

    await this.queueRepository.delete(id);

    return { message: 'Queue deleted successfully', deletedQueue: queue };
  }
}