import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common";
import { CustomerStatus, Prisma } from "@prisma/client";
import { PrismaService } from "../../infra/prisma/prisma.service";
import { CreateCustomerDto } from "./dto/create-customer.dto";
import { CustomerQueryDto } from "./dto/customer-query.dto";
import { UpdateCustomerDto } from "./dto/update-customer.dto";

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

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

    const where: Prisma.CustomerWhereInput = {
      companyId,
      ...(status ? { status } : {}),
      ...(type ? { type } : {}),
      ...(search
        ? {
            OR: [
              { name: { contains: search, mode: "insensitive" } },
              { document: { contains: search, mode: "insensitive" } },
              { email: { contains: search, mode: "insensitive" } },
              { phone: { contains: search, mode: "insensitive" } },
              { city: { contains: search, mode: "insensitive" } },
            ],
          }
        : {}),
    };

    const [items, total] = await Promise.all([
      this.prisma.customer.findMany({
        where,
        orderBy: { createdAt: "desc" },
        skip,
        take: limit,
        include: {
          _count: {
            select: {
              rentals: true,
              receivables: true,
              documents: true,
            },
          },
        },
      }),
      this.prisma.customer.count({ where }),
    ]);

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

  async getStats(companyId: string) {
    const [total, active, inactive, delinquent, totalCredit] = await Promise.all([
      this.prisma.customer.count({ where: { companyId } }),
      this.prisma.customer.count({ where: { companyId, status: CustomerStatus.ACTIVE } }),
      this.prisma.customer.count({ where: { companyId, status: CustomerStatus.INACTIVE } }),
      this.prisma.customer.count({ where: { companyId, status: CustomerStatus.DELINQUENT } }),
      this.prisma.customer.aggregate({
        where: { companyId },
        _sum: { creditLimit: true },
      }),
    ]);

    return {
      total,
      active,
      inactive,
      delinquent,
      totalCreditLimit: Number(totalCredit._sum.creditLimit || 0),
    };
  }

  async findOne(companyId: string, id: string) {
    const customer = await this.prisma.customer.findFirst({
      where: { id, companyId },
      include: {
        documents: { orderBy: { createdAt: "desc" } },
        rentals: {
          take: 5,
          orderBy: { createdAt: "desc" },
          select: {
            id: true,
            code: true,
            status: true,
            total: true,
            startDate: true,
            endDate: true,
          },
        },
        receivables: {
          take: 5,
          orderBy: { dueDate: "desc" },
          select: {
            id: true,
            description: true,
            amount: true,
            dueDate: true,
            status: true,
          },
        },
        _count: {
          select: { rentals: true, receivables: true, documents: true },
        },
      },
    });

    if (!customer) {
      throw new NotFoundException("Cliente não encontrado.");
    }

    return customer;
  }

  async create(companyId: string, dto: CreateCustomerDto) {
    const existing = await this.prisma.customer.findFirst({
      where: { companyId, document: dto.document },
    });

    if (existing) {
      throw new BadRequestException("Já existe um cliente cadastrado com este documento (CPF/CNPJ).");
    }

    return this.prisma.customer.create({
      data: {
        ...dto,
        companyId,
      },
    });
  }

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

    if (dto.document) {
      const existing = await this.prisma.customer.findFirst({
        where: {
          companyId,
          document: dto.document,
          NOT: { id },
        },
      });

      if (existing) {
        throw new BadRequestException("Outro cliente já possui este documento (CPF/CNPJ).");
      }
    }

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

  async remove(companyId: string, id: string) {
    await this.findOne(companyId, id);
    return this.prisma.customer.delete({
      where: { id },
    });
  }
}
