import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Coupon } from './coupon.entity';
import { IsNull } from 'typeorm';
import { ClaimedCoupon } from './claimedCoupon.entity';

@Injectable()
export class CouponsService {
  constructor(
    @InjectRepository(Coupon)
    private couponsRepository: Repository<Coupon>,
    @InjectRepository(ClaimedCoupon)
    private claimedCouponRepository: Repository<ClaimedCoupon>,
  ) { }

  async findOne(id: string): Promise<any> {
    return this.couponsRepository.findOne({
      where: { id, deletedAt: IsNull() },
    });
  }

  async findAll(
    where: any,
    page: number = 1,
    limit: number = 10,
    orderBy: string = 'createdAt',
    order: 'ASC' | 'DESC' = 'DESC',
  ): Promise<{ data: Coupon[], total: number }> {
    const [data, total] = await this.couponsRepository.findAndCount({
      where: { ...where, deletedAt: null },
      relations: ['company'], // Inclui a relação com a entidade `Company`
      take: limit,
      skip: (page - 1) * limit,
      order: { [orderBy]: order },
      select: {
        company: {
          id: true,
          cnpj: true,
          nome: true,
          permission: true, // Excluímos `senha` aqui explicitamente
        },
      },
    });

    return { data, total };
  }

  async claimCoupon(couponId: string, code: string, nomeCliente: string, cpf: string): Promise<void> {
    const coupon = await this.couponsRepository.findOne({
      where: { id: couponId, deletedAt: null },
      relations: ['company'],
    });

    if (!coupon) {
      throw new Error('Cupom não encontrado.');
    }

    const claimedCount = await this.claimedCouponRepository.count({
      where: { coupon: { id: couponId }, cpf },
    });

    if (claimedCount >= coupon.usageLimit) {
      throw new Error('Este CPF já atingiu o limite de usos para este cupom.');
    }

    const claimedCoupon = this.claimedCouponRepository.create({
      cpf,
      coupon,
      code,
      nomeCliente,
      company: coupon.company,
    });

    await this.claimedCouponRepository.save(claimedCoupon);
  }

  async findClaimedCoupons(filters: any): Promise<
    Array<{ cpf: string; code: string; companyName: string; companyCnpj: string; couponReference: string; claimedAt: Date }>
  > {
    const where: any = {};

    if (filters.cpf) {
      where.cpf = filters.cpf;
    }

    if (filters.company?.id) {
      where.company = { id: filters.company.id }; // Certifique-se de que o filtro de ID da companhia está correto
    }

    if (filters.coupon?.reference) {
      where.coupon = { reference: filters.coupon.reference }; // Certifique-se de que o filtro de referência do cupom está correto
    }

    const claimedCoupons = await this.claimedCouponRepository.find({
      where,
      relations: ['company', 'coupon'], // Inclui relações necessárias
    });

    return claimedCoupons.map((claimed) => ({
      cpf: claimed.cpf,
      code: claimed.code,
      companyName: claimed.company.nome,
      companyCnpj: claimed.company.cnpj,
      couponReference: claimed.coupon.reference,
      claimedAt: claimed.claimedAt,
      nomeCliente: claimed.nomeCliente,
      used: claimed.used,
    }));
  }

  async getAllClaimedCoupons(): Promise<any[]> {
    const claimedCoupons = await this.claimedCouponRepository.find({
      relations: ['company', 'coupon'], // Inclui as relações necessárias
    });
    return claimedCoupons.map((claimed) => ({
      id: claimed.id,
      cpf: claimed.cpf,
      code: claimed.code,
      companyName: claimed.company?.nome || 'N/A',
      companyCnpj: claimed.company?.cnpj || 'N/A',
      couponReference: claimed.coupon?.reference || 'N/A',
      claimedAt: claimed.claimedAt,
    }));
  }

  async upsert(couponData: any): Promise<any> {
    couponData.isActive = JSON.parse(couponData.isActive);
    if (!couponData.id || couponData.id === '0') {

      const newCoupon = this.couponsRepository.create(couponData);
      return this.couponsRepository.save(newCoupon);
    }

    const existingCoupon = await this.findOne(couponData.id);

    if (existingCoupon) {
      this.couponsRepository.merge(existingCoupon, couponData);

      console.log(existingCoupon);

      return this.couponsRepository.save(existingCoupon);
    }

    throw new Error('Cupom não encontrado para atualização.');
  }

  async activateCoupon(code: string): Promise<ClaimedCoupon> {
    if (!code) {
      throw new BadRequestException('Código do cupom é obrigatório.');
    }
  
    // Busca pelo código correto na tabela `ClaimedCoupon`
    const claimedCoupon = await this.claimedCouponRepository.findOne({ where: { code } });
  
    if (!claimedCoupon) {
      throw new NotFoundException('Cupom não encontrado.');
    }
  
    if (claimedCoupon.used) {
      throw new BadRequestException('O cupom já está inativo.');
    }
  
    // Marca o cupom como usado
    claimedCoupon.used = true;
  
    return await this.claimedCouponRepository.save(claimedCoupon);
  }

  async remove(id: string): Promise<void> {
    await this.couponsRepository.softDelete(id);
  }
}