import { Inject, Provide } from '@midwayjs/decorator';
import { BaseService, CoolCommException } from '@cool-midway/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
import * as _ from 'lodash';
import { KycEntity } from '../entity/kyc';
import { OrderService } from './order';
import { SunPayService } from './channels/sunpay';
import * as md5 from 'md5';

@Provide()
export class KycService extends BaseService {
  @InjectEntityModel(KycEntity)
  kycEntity: Repository<KycEntity>;

  @Inject()
  orderService: OrderService;

  @Inject()
  sunPayService: SunPayService

  async toPay(payload) {
    const { orderNo, customerId } = payload;
    const order = await this.orderService.findByOrderNo(orderNo);
    const customer = await this.kycEntity.findOneBy({ customerId })
    if (!orderNo || !order) {
      throw new CoolCommException('Order does not exist');
    }
    if (!customer) {
      throw new CoolCommException('Customer does not exist');
    }
    if (order.payUrl) {
      return {
        payUrl: order.payUrl
      };
    }
    const { payUrl, traceNo } = await this.sunPayService.createOrder({
      ...order,
      customerId,
      country: customer.country
    })
    order.payUrl = payUrl;
    order.traceNo = traceNo;
    await this.orderService.create(order);
    return {
      payUrl
    };
  }

  async createAdvanced(payload, files) {
    const kyc = await this.kycEntity.findOneBy({ customerId: payload.customerId });
    if (!payload.customerId || !kyc) {
      throw new CoolCommException('KYC user does not exist');
    }
    const fileObj = {};
    files.forEach(item => {
      fileObj[item.fieldName] = item
    })
    const data = await this.sunPayService.createAdvanced(payload, fileObj);
    await this.kycEntity.update(kyc.id, { level: '2' });
    return data;
  }

  async createPremium(payload, files) {
    const kyc = await this.kycEntity.findOneBy({ customerId: payload.customerId });
    if (!payload.customerId || !kyc) {
      throw new CoolCommException('KYC user does not exist');
    }
    const fileObj = {};
    files.forEach(item => {
      fileObj[item.fieldName] = item
    })
    const data = await this.sunPayService.createPremium(payload, fileObj);
    await this.kycEntity.update(kyc.id, { level: '3' });
    return data;
  }

  async createBasic(payload) {
    const { orderNo } = payload;
    const order = await this.orderService.findByOrderNo(orderNo);
    if (!orderNo || !order) {
      throw new CoolCommException('Order does not exist');
    }
    const kyc = await this.kycEntity.findOneBy({ email: payload.customerEmail });
    if (kyc) {
      throw new CoolCommException('This email has already been used');
    }
    const { customerId } = await this.sunPayService.createBasic(payload);
    if (customerId) {
      await this.kycEntity.insert({
        userId: order.userId,
        mchId: order.mchId,
        code: order.code,
        kycUserId: payload.outUserId,
        customerId: customerId,
        level: '1',
        email: payload.customerEmail,
        country: payload.countryCode
      })
      return { customerId }
    } else {
      throw new CoolCommException('Network exception, please try again later');
    }
  }

  async getCountries() {
    return await this.sunPayService.getCountries();
  }

  async getLevel(orderNo) {
    const order = await this.orderService.findByOrderNo(orderNo);
    if (!orderNo || !order) {
      throw new CoolCommException('Order does not exist');
    }
    const outUserId = md5(order.mchId + '_' + order.userId + 'v2');
    const data = {
      outUserId,
      level: 1,
      levelEnd: 3,
      customerId: '',
      payUrl: ''
    }
    const kyc = await this.kycEntity.findOneBy({
      userId: order.userId,
      code: order.code,
      mchId: order.mchId,
    });
    if (kyc) {
      data.level = +kyc.level + 1;
      data.customerId = kyc.customerId
    }
    const daily = await this.getDailyLevel(order, order.currency);
    const weekly = await this.getWeekLyLevel(order, order.currency);
    const monthly = await this.getMonthlyLevel(order, order.currency);
    data.levelEnd = Math.max(daily, weekly, monthly);
    console.log('---------', daily, weekly, monthly, data.level, data.levelEnd, data.customerId)
    data.payUrl = await this.validAndGetPayUrl(orderNo, data);
    return data;
  }

  async validAndGetPayUrl(orderNo, data) {
    if (data.level > data.levelEnd && data.customerId) {
      try {
        const { payUrl } = await this.toPay({
          orderNo: orderNo, customerId: data.customerId
        });
        return payUrl;
      } catch (e) {
        console.log('----发起订单失败-----')
        return "";
      }
    } else {
      return '';
    }
  }

  async getDailyLevel(order, currency) {
    const daily = await this.orderService.getDailyAmount(order.mchId, order.userId, order.code);
    let amount = 0;
    if (daily && daily[0]) {
      amount = +daily[0].total;
    }
    return this.getAmountLevel(amount + +order.amount, currency);
  }

  async getMonthlyLevel(order, currency) {
    const month = await this.orderService.getMonthlyAmount(order.mchId, order.userId, order.code);
    let amount = 0;
    if (month && month[0]) {
      amount = +month[0].total;
    }
    return this.getAmountLevel(amount + +order.amount, currency);
  }

  async getWeekLyLevel(order, currency) {
    const weekly = await this.orderService.getWeeklyAmount(order.mchId, order.userId, order.code);
    let amount = 0;
    if (weekly && weekly[0]) {
      amount = +weekly[0].total;
    }
    return this.getAmountLevel(amount + +order.amount, currency);
  }

  getAmountLevel(amount: number, currency) {
    const eur = this.toEur(amount, currency)
    console.log('转换为欧元：', amount, eur)
    if (eur <= 1000) {
      return 1;
    } else if (eur <= 5000) {
      return 2;
    } else {
      return 3;
    }
  }

  toEur(amount, currency) {
    switch (currency) {
      case "USD": return +((+amount / 1.0439).toFixed(2))
      case "AUD": return +((+amount / 1.6743).toFixed(2))
      case "MYR": return +((+amount / 4.6608).toFixed(2))
      case "JPY": return +((+amount / 164.69).toFixed(2))
      default: return amount
    }
  }

}
