import { Injectable, NotFoundException } from "@nestjs/common";
import { PrismaService } from "../../infra/prisma/prisma.service";
import { CreateScheduleEventDto, ScheduleEventStatus, ScheduleEventType } from "./dto/create-schedule-event.dto";
import { ScheduleQueryDto } from "./dto/schedule-query.dto";
import { UpdateScheduleEventDto } from "./dto/update-schedule-event.dto";

@Injectable()
export class ScheduleService {
  private customEvents: any[] = [];

  constructor(private readonly prisma: PrismaService) {}

  async findAll(companyId: string, query: ScheduleQueryDto) {
    const { search, type, status } = query;

    const [rentals, serviceOrders] = await Promise.all([
      this.prisma.rental.findMany({
        where: { companyId },
        include: {
          customer: true,
          items: { include: { equipment: true } },
        },
      }),
      this.prisma.serviceOrder.findMany({
        where: { companyId },
        include: { equipment: true },
      }),
    ]);

    const events: any[] = [];

    // Map rental deliveries and returns
    rentals.forEach((rental) => {
      const equip = rental.items[0]?.equipment;

      // Delivery event
      events.push({
        id: `evt-del-${rental.id}`,
        companyId: rental.companyId,
        title: `Entrega: ${equip ? `${equip.brand} ${equip.model}` : "Equipamento"}`,
        type: ScheduleEventType.DELIVERY,
        customerId: rental.customerId,
        equipmentId: equip?.id,
        startDate: rental.startDate.toISOString(),
        endDate: rental.startDate.toISOString(),
        location: rental.customer?.city ? `${rental.customer.street || "Obra"}, ${rental.customer.city}` : "Canteiro do Cliente",
        technician: rental.operator || "Equipe de Transporte",
        notes: `Mobilização do contrato ${rental.code}`,
        status: rental.status === "IN_PROGRESS" || rental.status === "FINISHED" ? ScheduleEventStatus.COMPLETED : ScheduleEventStatus.SCHEDULED,
        createdAt: rental.createdAt.toISOString(),
        customer: rental.customer,
        equipment: equip,
      });

      // Return event
      events.push({
        id: `evt-ret-${rental.id}`,
        companyId: rental.companyId,
        title: `Devolução: ${equip ? `${equip.brand} ${equip.model}` : "Equipamento"}`,
        type: ScheduleEventType.RETURN,
        customerId: rental.customerId,
        equipmentId: equip?.id,
        startDate: rental.endDate.toISOString(),
        endDate: rental.endDate.toISOString(),
        location: rental.customer?.city ? `${rental.customer.street || "Obra"}, ${rental.customer.city}` : "Pátio Central",
        technician: rental.operator || "Equipe de Coleta",
        notes: `Desmobilização do contrato ${rental.code}`,
        status: rental.status === "FINISHED" ? ScheduleEventStatus.COMPLETED : ScheduleEventStatus.SCHEDULED,
        createdAt: rental.createdAt.toISOString(),
        customer: rental.customer,
        equipment: equip,
      });
    });

    // Map service orders as MAINTENANCE events
    serviceOrders.forEach((so) => {
      events.push({
        id: `evt-maint-${so.id}`,
        companyId: so.companyId,
        title: `Manutenção: ${so.title}`,
        type: ScheduleEventType.MAINTENANCE,
        equipmentId: so.equipmentId,
        startDate: so.openedAt.toISOString(),
        endDate: so.openedAt.toISOString(),
        location: "Oficina Central / Canteiro",
        technician: "Técnico Mecânico",
        notes: so.description || `Ordem de Serviço ${so.code}`,
        status: so.status === "DONE" ? ScheduleEventStatus.COMPLETED : ScheduleEventStatus.SCHEDULED,
        createdAt: so.openedAt.toISOString(),
        equipment: so.equipment,
      });
    });

    // Combine mapped events with user created custom events
    const companyCustomEvents = this.customEvents.filter((e) => e.companyId === companyId);
    let filtered = [...events, ...companyCustomEvents];

    if (type) {
      filtered = filtered.filter((e) => e.type === type);
    }

    if (status) {
      filtered = filtered.filter((e) => e.status === status);
    }

    if (search) {
      const term = search.toLowerCase();
      filtered = filtered.filter(
        (e) =>
          e.title.toLowerCase().includes(term) ||
          (e.customer && e.customer.name.toLowerCase().includes(term)) ||
          (e.equipment && e.equipment.code.toLowerCase().includes(term))
      );
    }

    return {
      items: filtered,
      total: filtered.length,
    };
  }

  async getStats(companyId: string) {
    const res = await this.findAll(companyId, {});
    const items = res.items;

    const todayStr = new Date().toISOString().split("T")[0];
    const todayEvents = items.filter((e) => e.startDate.startsWith(todayStr)).length;
    const scheduledDeliveries = items.filter((e) => e.type === ScheduleEventType.DELIVERY && e.status === ScheduleEventStatus.SCHEDULED).length;
    const scheduledReturns = items.filter((e) => e.type === ScheduleEventType.RETURN && e.status === ScheduleEventStatus.SCHEDULED).length;
    const pendingMaintenance = items.filter((e) => e.type === ScheduleEventType.MAINTENANCE && e.status === ScheduleEventStatus.SCHEDULED).length;

    return {
      totalEvents: items.length,
      todayEvents,
      scheduledDeliveries,
      scheduledReturns,
      pendingMaintenance,
    };
  }

  async findOne(companyId: string, id: string) {
    const res = await this.findAll(companyId, {});
    const found = res.items.find((e) => e.id === id);
    if (!found) {
      throw new NotFoundException("Compromisso não encontrado na agenda.");
    }
    return found;
  }

  async create(companyId: string, dto: CreateScheduleEventDto) {
    let customer: any = null;
    if (dto.customerId) {
      try {
        customer = await this.prisma.customer.findUnique({ where: { id: dto.customerId } });
      } catch {}
    }

    let equipment: any = null;
    if (dto.equipmentId) {
      try {
        equipment = await this.prisma.equipment.findUnique({ where: { id: dto.equipmentId } });
      } catch {}
    }

    const newEvt = {
      id: `evt-custom-${Date.now()}`,
      companyId,
      title: dto.title,
      type: dto.type,
      customerId: dto.customerId || null,
      equipmentId: dto.equipmentId || null,
      startDate: dto.startDate,
      endDate: dto.endDate,
      location: dto.location || "Canteiro de Obras",
      technician: dto.technician || "Equipe de Logística",
      notes: dto.notes || null,
      status: dto.status || ScheduleEventStatus.SCHEDULED,
      createdAt: new Date().toISOString(),
      customer,
      equipment,
    };

    this.customEvents.unshift(newEvt);
    return newEvt;
  }

  async update(companyId: string, id: string, dto: UpdateScheduleEventDto) {
    const idx = this.customEvents.findIndex((e) => e.id === id);
    if (idx !== -1) {
      let customer = this.customEvents[idx].customer;
      if (dto.customerId && dto.customerId !== this.customEvents[idx].customerId) {
        try {
          customer = await this.prisma.customer.findUnique({ where: { id: dto.customerId } });
        } catch {}
      }

      let equipment = this.customEvents[idx].equipment;
      if (dto.equipmentId && dto.equipmentId !== this.customEvents[idx].equipmentId) {
        try {
          equipment = await this.prisma.equipment.findUnique({ where: { id: dto.equipmentId } });
        } catch {}
      }

      const updated = {
        ...this.customEvents[idx],
        ...dto,
        customer,
        equipment,
        updatedAt: new Date().toISOString(),
      };
      this.customEvents[idx] = updated;
      return updated;
    }

    try {
      const found = await this.findOne(companyId, id);
      if (id.startsWith("evt-maint-")) {
        const soId = id.replace("evt-maint-", "");
        if (dto.status === ScheduleEventStatus.COMPLETED) {
          await this.prisma.serviceOrder.update({
            where: { id: soId },
            data: { status: "DONE" },
          }).catch(() => {});
        }
      } else if (id.startsWith("evt-ret-")) {
        const rentalId = id.replace("evt-ret-", "");
        if (dto.status === ScheduleEventStatus.COMPLETED) {
          await this.prisma.rental.update({
            where: { id: rentalId },
            data: { status: "FINISHED" },
          }).catch(() => {});
        }
      }
      return {
        ...found,
        ...dto,
        updatedAt: new Date().toISOString(),
      };
    } catch {
      return {
        id,
        companyId,
        title: dto.title || "Agendamento",
        type: dto.type || ScheduleEventType.DELIVERY,
        startDate: dto.startDate || new Date().toISOString(),
        endDate: dto.endDate || new Date().toISOString(),
        status: dto.status || ScheduleEventStatus.COMPLETED,
        ...dto,
      };
    }
  }

  async remove(companyId: string, id: string) {
    this.customEvents = this.customEvents.filter((e) => e.id !== id);
    return { success: true };
  }
}
