import {
  BadRequestException,
  Injectable,
  NotFoundException,
} from '@nestjs/common';
import { CreateOfferDto } from './dto/create-offer.dto';
import { UpdateOfferDto } from './dto/update-offer.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { Offer } from './entities/offer.entity';
import { IsNull, Not, Repository } from 'typeorm';
import { OffersRepository } from './offers.repository';
import isValidUuidV4 from 'src/common/uuid validator/uuid-validate';
import { lan } from 'src/lan';
import { isEmpty } from 'src/common/helper';
import { AppUser } from 'src/app_users/entities/app_user.entity';
import { SendNotificationService } from 'src/common/push-notification';

@Injectable()
export class OffersService {
  constructor(
    @InjectRepository(Offer)
    private readonly offersEntity: Repository<Offer>,
    private readonly offersRepository: OffersRepository,
    @InjectRepository(AppUser)
    private readonly appUserRepository: Repository<AppUser>,
    private readonly sendNotificationService: SendNotificationService,
  ) {}

  async create(createOfferDto: CreateOfferDto) {
    const createOffer: CreateOfferDto = new Offer();
    Object.assign(createOffer, createOfferDto);
    const returnData = await this.offersEntity.save(createOffer);

    const maxDescriptionLength = 30;
    const limitedDescription =
      createOfferDto.description.length > maxDescriptionLength
        ? createOfferDto.description.substring(0, maxDescriptionLength) + '...'
        : createOfferDto.description;

    const usersWithFcmTokens = await this.appUserRepository.find({
      where: { fcm_token: Not(IsNull()), notify: true },
      select: ['fcm_token', 'id'],
    });

    const fcmTokens = usersWithFcmTokens.map((user) => user.fcm_token);

    if (fcmTokens.length > 0) {
      for (const user of usersWithFcmTokens) {
        const fcmToken = user.fcm_token;
        const extraData = {
          user_id: user.id.toString(),
          link: createOfferDto.link,
        };

        await this.sendNotificationService.send(
          [fcmToken],
          createOfferDto.title,
          limitedDescription,
          extraData,
        );
      }
    }

    return returnData;
  }

  async findAllOffers(
    take: number,
    skip: number,
    search: string,
    headers: any,
  ) {
    return await this.offersRepository.findAll(take, skip, search, headers);
  }

  async findOffer(id: string) {
    if (!isValidUuidV4(id)) {
      throw new BadRequestException(lan('common.invalid_uuid_format'));
    }

    const offer = await this.offersRepository.findOfferDetails(id);

    if (isEmpty(offer)) {
      throw new NotFoundException(lan('common.data_not_found'));
    }

    return offer;
  }

  async updateOffer(id: string, updateOfferDto: UpdateOfferDto) {
    if (!isValidUuidV4(id)) {
      throw new BadRequestException(lan('common.invalid_uuid_format'));
    }

    const offer = await this.offersRepository.findOne(id);

    if (isEmpty(offer)) {
      throw new NotFoundException(lan('common.data_not_found'));
    }

    Object.assign(offer, updateOfferDto);

    return await this.offersEntity.update(id, offer);
  }

  async removeOffer(id: string) {
    if (!isValidUuidV4(id)) {
      throw new BadRequestException(lan('common.invalid_uuid_format'));
    }

    const offer = await this.offersRepository.findOne(id);

    if (isEmpty(offer)) {
      throw new NotFoundException(lan('common.data_not_found'));
    }

    return this.offersEntity.softDelete(id);
  }
}
