import { Init, Inject, Provide } from '@midwayjs/decorator';
import { BaseService, CoolCommException } from '@cool-midway/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Equal, In, Repository } from 'typeorm';
import { OrderInfoEntity } from '../entity/info';
import { OrderGoodsService } from './goods';
import { OrderGoodsEntity } from '../entity/goods';
import * as moment from 'moment';
import { UserAddressService } from '../../user/service/address';
import { Action, OrderQueue } from '../queue/order';
import { OrderPayService } from './pay';
import { PluginService } from '../../plugin/service/info';
import { GoodsSpecEntity } from '../../goods/entity/spec';
import { MarketCouponInfoService } from '../../market/service/coupon/info';
import { MarketCouponUserEntity } from '../../market/entity/coupon/user';
import { BaseSysParamService } from '../../base/service/sys/param';
import BigNumber from 'bignumber.js';

/**
 * 订单信息
 */
@Provide()
export class OrderInfoService extends BaseService {
  @InjectEntityModel(OrderInfoEntity)
  orderInfoEntity: Repository<OrderInfoEntity>;

  @InjectEntityModel(GoodsSpecEntity)
  goodsSpecEntity: Repository<GoodsSpecEntity>;

  @InjectEntityModel(MarketCouponUserEntity)
  marketCouponUserEntity: Repository<MarketCouponUserEntity>;

  @Inject()
  orderGoodsService: OrderGoodsService;

  @Inject()
  userAddressService: UserAddressService;

  @Inject()
  orderPayService: OrderPayService;

  @Inject()
  orderQueue: OrderQueue;

  @Inject()
  pluginService: PluginService;

  @Inject()
  marketCouponInfoService: MarketCouponInfoService;

  @Inject()
  baseSysParamService: BaseSysParamService;

  @Init()
  async init() {
    await super.init();
    this.setEntity(this.orderInfoEntity);
  }

  /**
   * 修改前
   * @param data
   * @param type
   */
  async modifyBefore(data: any, type: 'add' | 'update' | 'delete') {
    if (type == 'add' || type == 'update') {
      delete data.refundStatus;
      delete data.refundApplyTime;
    }
  }

  /**
   * 分页查询
   * @param query
   * @param option
   * @param connectionName
   */
  async page(query: any, option: any, connectionName?: any) {
    const result = await super.page(query, option, connectionName);
    // 筛选条件的非分页sql
    const countSql = await super.getOptionFind(query, option);

    const countResult = await this.nativeQuery(
      `SELECT COUNT(a.id) as totalCount, SUM(a.price) as totalPrice FROM ${
        countSql.split('FROM')[1].split('ORDER BY')[0]
      }`
    );

    result['subData'] = {
      totalCount: countResult[0].totalCount,
      totalPrice: countResult[0].totalPrice,
    };

    const goodsList = await this.orderGoodsService.getByOrderIds(
      result.list.map(e => e.id)
    );
    for (const item of result.list) {
      item.goodsList = goodsList.filter(e => e.orderId == item.id);
    }
    return result;
  }

  /**
   * 根据订单号获取订单
   * @param orderNum
   * @returns
   */
  async getByOrderNum(orderNum: string) {
    return this.orderInfoEntity.findOneBy({
      orderNum: Equal(orderNum),
    });
  }

  /**
   * 修改订单状态
   * @param id
   * @param status
   */
  async changeStatus(id: number, status: number) {
    await this.orderInfoEntity.update({ id }, { status });
  }

  /**
   * 关闭订单
   * @param orderId
   * @param remark
   */
  async close(orderId: number, remark: string) {
    const order = await this.info(orderId);
    if (!order || !remark)
      throw new CoolCommException('订单不存在或备注不能为空');
    if (order.status != 0) {
      throw new CoolCommException('订单状态不允许关闭');
    }

    // 退回优惠券
    if (order.discountSource && order.discountPrice > 0) {
      if (order.discountSource.type == 0) {
        this.marketCouponUserEntity.update(
          {
            id: order.discountSource.objectId,
          },
          {
            status: 0,
          }
        );
      }
    }

    await this.orderInfoEntity.update(
      { id: orderId },
      { status: 7, closeRemark: remark }
    );

    // 释放库存
    await this.orderGoodsService.updateStock(order.goodsList, 'add');
  }

  /**
   * 订单详情
   * @param id
   * @param infoIgnoreProperty
   */
  async info(id: any, infoIgnoreProperty?: string[]) {
    const info = await super.info(id, infoIgnoreProperty);
    if (!info) {
      throw new CoolCommException('订单不存在');
    }
    if (info) {
      // 获取商品
      info.goodsList = await this.orderGoodsService.getByOrderId(info.id);
    }
    return info;
  }

  /**
   * 创建订单
   * @param data
   */
  async create(data: {
    userId: number;
    goodsList: OrderGoodsEntity[];
    addressId: number;
    remark: string;
    title: string;
    couponId?: number;
  }) {
    const address = await this.userAddressService.info(data.addressId);
    const order = {
      userId: data.userId,
      address,
      remark: data.remark,
      title: data.title,
      goodsList: data.goodsList,
    } as OrderInfoEntity;
    // 检查库存
    await this.checkStock(data.goodsList);
    order.price = await this.orderGoodsService.getTotalPrice(data.goodsList);
    order.goodsList = data.goodsList;

    // 使用优惠券
    if (data.couponId) {
      await this.marketCouponInfoService.checkAndUse(
        data.couponId,
        data.userId,
        order
      );
    }
    await this.orderInfoEntity.insert(order);

    // 生成订单号
    const orderNum = await this.generateOrderNum(order.id);

    // 更新订单
    await this.orderInfoEntity.update(order.id, {
      orderNum,
    });

    // 保存订单商品
    await this.orderGoodsService.save(order.id, data.goodsList);

    // 更新商品库存
    await this.orderGoodsService.updateStock(data.goodsList);

    const orderTimeout = await this.baseSysParamService.dataByKey(
      'orderTimeout'
    );
    // 发送订单创建消息
    this.orderQueue.add(
      { orderId: order.id, action: Action.TIMEOUT },
      {
        // 超时关闭订单
        delay: orderTimeout * 60 * 1000,
      }
    );
    return order;
  }

  /**
   * 生成订单号
   * @param orderId
   */
  async generateOrderNum(orderId: number, label = 'U') {
    const orderNum =
      moment().format('YYYYMMDDHHmmss') +
      Math.floor(Math.random() * 10000).toString() +
      orderId.toString();
    return label + orderNum;
  }

  /**
   * 退款
   * @param userId
   * @param orderId
   * @param goodsId
   * @param reason
   */
  async refund(userId: number, orderId: number, reason: string) {
    const order = await this.info(orderId);
    if (order && order.userId != userId) {
      throw new CoolCommException('非法操作');
    }
    if (![1, 2].includes(order.status)) {
      throw new CoolCommException('订单状态不允许退款');
    }

    await this.orderInfoEntity.update(
      { id: Equal(orderId) },
      {
        status: 5,
        refund: {
          amount: new BigNumber(order.price)
            .minus(order.discountPrice)
            .toNumber(),
          status: 0,
          applyTime: new Date(),
          reason,
          orderNum: 'R' + order.orderNum.slice(1),
        },
      }
    );
  }

  /**
   * 退款处理
   * @param orderId
   * @param action 0-拒绝 1-同意
   * @param refuseReason 0-拒绝 1-同意
   * @param amount
   */
  async refundHandle(
    orderId: number,
    action: number,
    refuseReason: string,
    amount: number
  ) {
    const order = await this.info(orderId);
    if (order.status != 5 || !order.refund) {
      throw new CoolCommException('订单状态不允许退款处理');
    }
    // 拒绝退款
    if (action == 0) {
      await this.orderInfoEntity.update(
        { id: Equal(orderId) },
        {
          status: 4,
          refund: {
            ...order.refund,
            status: 2,
            refuseReason: refuseReason,
          },
        }
      );
    }
    // 同意退款
    if (action == 1) {
      if (amount > order.price) {
        throw new CoolCommException('退款金额不能大于订单金额');
      }
      // 执行退款操作
      const result = await this.orderPayService.wxRefund(order, amount);

      if (result) {
        await this.orderInfoEntity.update(
          { id: Equal(orderId) },
          {
            status: 6,
            refund: {
              ...order.refund,
              status: 1,
              realAmount: amount,
              time: new Date(),
            },
          }
        );
      }
    }
  }

  /**
   * 确认收货
   * @param userId
   * @param orderId
   */
  async confirm(orderId: number, userId: number) {
    const order = await this.info(orderId);
    if (order && order.userId != userId) {
      throw new CoolCommException('非法操作');
    }
    if (![2].includes(order.status)) {
      throw new CoolCommException('订单状态不允许退款');
    }
    await this.orderInfoEntity.update(
      { id: Equal(orderId) },
      {
        status: 3,
      }
    );
  }

  /**
   * 自动确认收货
   * @param orderId
   * @returns
   */
  async autoConfirm(orderId: number) {
    const info = await this.orderInfoEntity.findOneBy({ id: Equal(orderId) });
    if (info.status != 2) {
      return;
    }
    await this.orderInfoEntity.update({ id: Equal(orderId) }, { status: 3 });
  }

  /**
   * 物流信息
   * @param orderId
   */
  async logistics(orderId: number, userId?: number) {
    const order: OrderInfoEntity = await this.info(orderId);
    if (userId && order.userId != userId) {
      throw new CoolCommException('非法操作');
    }
    const no = order.logistics?.num;

    if (!no) {
      return null;
    }

    const instance = await this.pluginService.getInstance('wuliu');
    return await instance.query(no);
  }

  /**
   * 发货
   * @param orderId
   * @param logistics
   */
  async deliver(
    orderId: number,
    logistics: {
      // 物流公司
      company: string;
      // 物流单号
      num: string;
    }
  ) {
    const order: OrderInfoEntity = await this.info(orderId);
    if (order.status != 1) {
      throw new CoolCommException('订单状态不允许发货');
    }
    await this.orderInfoEntity.update(orderId, {
      status: 2,
      logistics,
    });
  }

  /**
   * 检查库存
   * @param goodsList
   */
  async checkStock(goodsList: OrderGoodsEntity[]) {
    const specs = goodsList.map(item => item.spec);
    const specList = await this.goodsSpecEntity.findBy({
      id: In(specs.map(e => e.id)),
    });
    for (const spec of specList) {
      const goods = goodsList.find(e => e.spec.id == spec.id);
      // 设置商品价格
      goods.price = spec.price;
      if (goods.count > spec.stock) {
        throw new CoolCommException(`商品[${goods.goodsInfo.title}]，库存不足`);
      }
    }
  }

  /**
   * 用户订单数量
   * @param userId
   */
  async userCount(userId: number) {
    const statusLabels = [
      '待付款',
      '待发货',
      '待收货',
      '待评价',
      '交易完成',
      '退款中',
      '已退款',
      '已关闭',
    ];
    // 生成查询字符串
    const selectQueries = statusLabels.map(
      (label, index) =>
        `SUM(CASE WHEN status = ${index} THEN 1 ELSE 0 END) AS '${label}'`
    );
    const list = await this.orderInfoEntity
      .createQueryBuilder('a')
      .select(selectQueries)
      .where('a.userId = :userId', { userId })
      .getRawMany();
    return list[0];
  }
}
