import { Inject, Injectable, forwardRef } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { ErrorService } from '../../error/error.service';
import {
  NegativeScoreEntity,
  NegativeScoreStatus,
  NegativeScoreType,
} from './entities/negative-score.entity';
import { UserEntity } from '../user/entities/user.entity';
import { SiteInfoService } from '../siteInfo/site-info.service';
import { VeneshService } from 'src/thirdParty/venesh/venesh.service';
import {
  applyFiltersToBuilder,
  applySortingToBuilder,
  paginationResult,
} from 'src/utils';
import { CreateNegativeScoreRequestDto } from './dto/create-negative-score-request.dto';
import { PaymentService } from '../payment/payment.service';
import { PaymentType } from '../payment/entities/payment.entity';
import { PayNegativeScoreInquiryDto } from './dto/pay-negative-score-inquiry.dto';
import { UserService } from '../user/user.service';
import { GhabzinoService } from '../../thirdParty/ghabzino/ghabzino.service';

@Injectable()
export class NegativeScoreService {
  constructor(
    @InjectRepository(NegativeScoreEntity)
    private negativeScoreRepository: Repository<NegativeScoreEntity>,
    private error: ErrorService,
    private veneshService: VeneshService,
    private ghabzinoService: GhabzinoService,
    private userService: UserService,
    private siteInfoService: SiteInfoService,

    @Inject(forwardRef(() => PaymentService))
    private readonly paymentService: PaymentService,
  ) {}

  /**
   * -------------------------------------------------------
   * POST /negative-scores/request/me
   */
  async addRequest(dto: CreateNegativeScoreRequestDto, user: UserEntity) {
    const setting = await this.siteInfoService.getInfo([
      'negativeScoreInquiryBasicAmount',
      'negativeScoreInquiryAdvancedAmount',
    ]);

    let inquiryAmount = 0;
    // if (dto.type === NegativeScoreType.basic) {
    //   inquiryAmount = setting.negativeScoreInquiryBasicAmount;
    // } else {
    inquiryAmount = setting.negativeScoreInquiryAdvancedAmount;
    // }

    const { identifiers } = await this.negativeScoreRepository
      .createQueryBuilder()
      .insert()
      .values({
        ...dto,
        type: NegativeScoreType.advanced, // hard code
        userId: user.id,
        inquiryAmount,
        status: inquiryAmount
          ? NegativeScoreStatus.pending
          : NegativeScoreStatus.paid_inquiry,
        licenseNumber: dto.licenseNumber,
        createdAt: new Date(),
        updatedAt: new Date(),
      })
      .execute();

    return { id: identifiers[0].id };
  }

  /**
   * -------------------------------------------------------
   * POST /negative-scores/pay-inquiry/me
   */
  async payInquiry(dto: PayNegativeScoreInquiryDto, user: UserEntity) {
    const negativeScore = await this.negativeScoreRepository.findOne({
      where: {
        id: dto.negativeScoreId,
        userId: user.id,
        status: NegativeScoreStatus.pending,
      },
      relations: ['user'],
    });

    if (!negativeScore) {
      this.error.unprocessableEntity(['درخواست شما نامعتبر است']);
    }

    let bankPayAmount = negativeScore.inquiryAmount;
    let usedWalletAmount = null;

    // Using the wallet
    if (dto.useWallet) {
      const totalWallet = user.realWallet + user.virtualWallet;

      // Enough money in wallet
      if (totalWallet >= negativeScore.inquiryAmount) {
        negativeScore.status = NegativeScoreStatus.paid_inquiry;
        await negativeScore.save();

        await this.userService.reduceBothWallets(
          user.id,
          negativeScore.inquiryAmount,
        );

        return { bankUrl: null, paid: true };
      }

      // After payment, totalWallet will be reduced from the wallet
      bankPayAmount -= totalWallet;
      usedWalletAmount = totalWallet;
    }

    // Going to the bank
    const { paymentId, bankUrl } = await this.paymentService.createPayLink(
      bankPayAmount,
      usedWalletAmount,
      PaymentType.negative_inquiry,
      dto.payGateway,
      negativeScore.id,
      user,
    );

    negativeScore.paymentInquiryId = paymentId;
    await negativeScore.save();

    return { bankUrl, paid: false };
  }

  /**
   * -------------------------------------------------------
   * GET /negative-scores/1/do-inquiry/me
   * call from front or payment service
   */
  async doInquiry(
    paymentId: number = null,
    negativeScoreId: number = null,
    user: UserEntity = null,
  ) {
    let negativeScore: NegativeScoreEntity;

    // Request from front-end
    if (negativeScoreId) {
      negativeScore = await this.negativeScoreRepository.findOne({
        where: { id: negativeScoreId, userId: user.id },
        relations: ['user'],
      });

      if (
        negativeScore?.inquiryAmount &&
        negativeScore?.status === NegativeScoreStatus.pending
      ) {
        this.error.unprocessableEntity(['درخواست شما نامعتبر است']);
      }
    }
    // Request after payment by paymentService
    else {
      negativeScore = await this.negativeScoreRepository.findOne({
        where: { paymentInquiryId: paymentId },
        relations: ['user'],
      });
    }

    // Already inquired the negativeScore
    if (negativeScore.status === NegativeScoreStatus.inquired) {
      delete negativeScore.user;
      return negativeScore;
    }

    negativeScore.status = NegativeScoreStatus.paid_inquiry;
    await negativeScore.save();

    // Inquiring the negativeScore
    // if (negativeScore.type === NegativeScoreType.basic) {
    //   const result = await this.veneshService.negativeScoreInquiry(
    //     negativeScore.licenseNumber,
    //   );

    //   // update negativeScore with result
    //   negativeScore.negativeScore = result.NegativeScore;
    //   negativeScore.offenseCount = +result.OffenseCount;
    //   negativeScore.status = NegativeScoreStatus.inquired;
    //   await negativeScore.save();
    // } else {

    // const result = await this.veneshService.advancedNegativeScoreInquiry(
    //   negativeScore.licenseNumber,
    //   negativeScore.user.nationalCode,
    //   negativeScore.user.mobile,
    // );

    // update negativeScore with result (venesh)
    // negativeScore.negativeScore = result.NegativeScore;
    // negativeScore.allowedToDrive = result.AllowedToDrive === 1;
    // negativeScore.rule = result.Rule;
    // negativeScore.status = NegativeScoreStatus.inquired;
    // negativeScore.updatedAt = new Date();
    // await negativeScore.save();

    const result = await this.ghabzinoService.negativeScoreInquiry(
      negativeScore.user.nationalCode,
      negativeScore.user.mobile,
      negativeScore.licenseNumber,
    );

    // update negativeScore with result (ghabzino)
    negativeScore.allowedToDrive = result.AllowedToDrive;
    negativeScore.rule = result.Rule;
    negativeScore.negativeScore = result.NegativeScore;
    negativeScore.status = NegativeScoreStatus.inquired;
    negativeScore.updatedAt = new Date();
    await negativeScore.save();
    // }

    delete negativeScore.user;

    return negativeScore;
  }

  /**
   * -------------------------------------------------------
   * GET /negative-scores
   */
  async getAll(
    page = 1,
    limit = 20,
    filters = null,
    sorts = null,
    userId = null,
  ) {
    let builder = this.negativeScoreRepository
      .createQueryBuilder('negativeScore')

      .innerJoin('negativeScore.user', 'user')
      .addSelect(['user.id', 'user.name', 'user.surName', 'user.mobile'])

      .take(limit)
      .skip((page - 1) * limit);

    if (sorts) {
      builder = applySortingToBuilder(builder, sorts);
    } else {
      builder.orderBy('negativeScore.createdAt', 'DESC');
    }

    builder = applyFiltersToBuilder(builder, filters);

    if (userId) {
      builder.andWhere({ userId });
    }
    const [items, totalItems] = await builder.getManyAndCount();

    return {
      items,
      pagination: paginationResult(page, limit, totalItems),
    };
  }

  /**
   * -------------------------------------------------------
   * GET /negative-scores/1
   */
  async getById(id: number, userId = null) {
    const builder = this.negativeScoreRepository
      .createQueryBuilder('negativeScore')

      .innerJoin('negativeScore.user', 'user')
      .addSelect(['user.id', 'user.name', 'user.surName', 'user.mobile'])
      .andWhere({ id });

    if (userId) {
      builder.andWhere({ userId });
    }

    return await builder.getOne();
  }
}
