import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common";
import { Prisma } from "@prisma/client";
import { PrismaService } from "../../infra/prisma/prisma.service";
import { CategoryQueryDto } from "./dto/category-query.dto";
import { CreateCategoryDto } from "./dto/create-category.dto";
import { UpdateCategoryDto } from "./dto/update-category.dto";

@Injectable()
export class CategoriesService {
  constructor(private readonly prisma: PrismaService) {}

  async findAll(companyId: string, query: CategoryQueryDto) {
    const { search, page = 1, limit = 20 } = query;
    const skip = (page - 1) * limit;

    const where: Prisma.CategoryWhereInput = {
      companyId,
      ...(search
        ? {
            OR: [
              { name: { contains: search, mode: "insensitive" } },
              { description: { contains: search, mode: "insensitive" } },
            ],
          }
        : {}),
    };

    const [items, total] = await Promise.all([
      this.prisma.category.findMany({
        where,
        orderBy: { name: "asc" },
        skip,
        take: limit,
        include: {
          _count: {
            select: { equipment: true },
          },
        },
      }),
      this.prisma.category.count({ where }),
    ]);

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

  async getStats(companyId: string) {
    const categories = await this.prisma.category.findMany({
      where: { companyId },
      include: {
        _count: {
          select: { equipment: true },
        },
      },
    });

    const totalCategories = categories.length;
    const totalEquipment = categories.reduce((acc, cat) => acc + cat._count.equipment, 0);

    const sortedByEquipment = [...categories].sort(
      (a, b) => b._count.equipment - a._count.equipment
    );
    const topCategory = sortedByEquipment[0]
      ? { name: sortedByEquipment[0].name, count: sortedByEquipment[0]._count.equipment }
      : null;

    return {
      totalCategories,
      totalEquipment,
      topCategory,
    };
  }

  async findOne(companyId: string, id: string) {
    const category = await this.prisma.category.findFirst({
      where: { id, companyId },
      include: {
        equipment: {
          orderBy: { createdAt: "desc" },
          select: {
            id: true,
            code: true,
            assetTag: true,
            brand: true,
            model: true,
            dailyRate: true,
            status: true,
          },
        },
        _count: {
          select: { equipment: true },
        },
      },
    });

    if (!category) {
      throw new NotFoundException("Categoria não encontrada.");
    }

    return category;
  }

  async create(companyId: string, dto: CreateCategoryDto) {
    const existing = await this.prisma.category.findFirst({
      where: { companyId, name: { equals: dto.name, mode: "insensitive" } },
    });

    if (existing) {
      throw new BadRequestException("Já existe uma categoria cadastrada com este nome.");
    }

    return this.prisma.category.create({
      data: {
        ...dto,
        companyId,
        color: dto.color || "#2563eb",
      },
    });
  }

  async update(companyId: string, id: string, dto: UpdateCategoryDto) {
    await this.findOne(companyId, id);

    if (dto.name) {
      const existing = await this.prisma.category.findFirst({
        where: {
          companyId,
          name: { equals: dto.name, mode: "insensitive" },
          NOT: { id },
        },
      });

      if (existing) {
        throw new BadRequestException("Outra categoria já possui este nome.");
      }
    }

    return this.prisma.category.update({
      where: { id },
      data: dto,
    });
  }

  async remove(companyId: string, id: string) {
    const category = await this.findOne(companyId, id);

    if (category._count.equipment > 0) {
      throw new BadRequestException(
        `Não é possível excluir a categoria pois existem ${category._count.equipment} equipamentos vinculados a ela.`
      );
    }

    return this.prisma.category.delete({
      where: { id },
    });
  }
}
