import { Inject, Provide } from '@midwayjs/core';
import { BaseService, CoolCommException, CoolTransaction } from '@cool-midway/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { QueryRunner, Repository } from 'typeorm';
import * as moment from 'moment';
import { UserInfoEntity } from '../../user/entity/info';
import { BasicdataSorterEntity } from '../../basicdata/entity/sorter';
import { RecycleOrderEntity } from '../entity/recycleorder';
import { RecycleOrderItemEntity } from '../entity/recycleorderitem';
import { RecycleItemEntity } from '../entity/recycleitem';
import { RecycleTransactionEntity } from '../entity/transaction';
import { RecycleAppointmentEntity } from '../entity/recycleappointment';
import { RecycleAppointmentLogEntity } from '../entity/recycleappointmentlog';
import { BaseSysParamService } from '../../base/service/sys/param';

/**
 * 分拣员 App 业务
 */
@Provide()
export class ShopSorterService extends BaseService {
  @InjectEntityModel(UserInfoEntity)
  userInfoEntity: Repository<UserInfoEntity>;

  @InjectEntityModel(BasicdataSorterEntity)
  basicdataSorterEntity: Repository<BasicdataSorterEntity>;

  @InjectEntityModel(RecycleOrderEntity)
  recycleOrderEntity: Repository<RecycleOrderEntity>;

  @InjectEntityModel(RecycleOrderItemEntity)
  recycleOrderItemEntity: Repository<RecycleOrderItemEntity>;

  @InjectEntityModel(RecycleItemEntity)
  recycleItemEntity: Repository<RecycleItemEntity>;

  @InjectEntityModel(RecycleTransactionEntity)
  recycleTransactionEntity: Repository<RecycleTransactionEntity>;

  @InjectEntityModel(RecycleAppointmentEntity)
  recycleAppointmentEntity: Repository<RecycleAppointmentEntity>;

  @InjectEntityModel(RecycleAppointmentLogEntity)
  recycleAppointmentLogEntity: Repository<RecycleAppointmentLogEntity>;

  @Inject()
  baseSysParamService: BaseSysParamService;

  /**
   * 读取打卡参数
   */
  async getHitupConfig() {
    const scoreRaw = await this.baseSysParamService.dataByKey('hitup.score');
    const maxRaw = await this.baseSysParamService.dataByKey(
      'hitup.maxmium.perday'
    );
    const score = Number(scoreRaw);
    const maxPerDay = Number(maxRaw);
    return {
      score: Number.isFinite(score) && score >= 0 ? score : 1,
      maxPerDay: Number.isFinite(maxPerDay) && maxPerDay >= 0 ? maxPerDay : 1,
    };
  }

  /**
   * 校验分拣员
   */
  async getSorter(sorterId: string) {
    const id = String(sorterId || '').trim();
    if (!id) {
      throw new CoolCommException('缺少分拣员信息');
    }
    const sorter = await this.basicdataSorterEntity.findOneBy({
      businessId: id,
    });
    if (!sorter || sorter.status !== 0) {
      throw new CoolCommException('分拣员账号不可用');
    }
    return sorter;
  }

  /**
   * 校验回收码对应的平台用户（回收码即为 unionid）
   */
  async checkUser(unionid: string) {
    const uid = String(unionid || '').trim();
    if (!uid) {
      throw new CoolCommException('请扫描有效的回收码');
    }
    const user = await this.userInfoEntity.findOneBy({ unionid: uid });
    if (!user || user.status !== 1) {
      throw new CoolCommException('该用户不是平台用户');
    }
    return {
      unionid: user.unionid,
      nickName: user.nickName,
      phone: user.phone,
      role: user.role,
      departmentId: user.departmentId,
      carbonBalance: user.carbonBalance,
      collegeName: user.collegeName,
      className: user.className,
      avatarUrl: user.avatarUrl,
    };
  }

  /**
   * 打卡积分
   */
  @CoolTransaction()
  async checkIn(
    param: { unionid: string; sorterId: string },
    queryRunner?: QueryRunner
  ) {
    if (!queryRunner) {
      throw new CoolCommException('事务启动失败');
    }
    const manager = queryRunner.manager;
    const unionid = String(param.unionid || '').trim();
    const sorter = await this.getSorter(param.sorterId);
    const user = await manager.findOne(UserInfoEntity, {
      where: { unionid },
    });
    if (!user || user.status !== 1) {
      throw new CoolCommException('该用户不是平台用户');
    }

    const { score, maxPerDay } = await this.getHitupConfig();
    const today = moment().format('YYYY-MM-DD');
    const todayCount = await manager
      .createQueryBuilder(RecycleOrderEntity, 'a')
      .where('a.campusUserId = :unionid', { unionid })
      .andWhere('a.orderType = :orderType', { orderType: '打卡' })
      .andWhere('a.createTime >= :start AND a.createTime <= :end', {
        start: `${today} 00:00:00`,
        end: `${today} 23:59:59`,
      })
      .getCount();

    if (todayCount >= maxPerDay) {
      throw new CoolCommException('该用户今日打卡次数已达上限');
    }

    const orderNo = this.genOrderNo('CI');
    const now = moment().format('YYYY-MM-DD HH:mm:ss');
    const order = await manager.save(RecycleOrderEntity, {
      orderNo,
      orderType: '打卡',
      campusUserId: unionid,
      departmentId: user.departmentId,
      siteId: sorter.workSiteId,
      sorterId: sorter.businessId,
      status: '已完成',
      totalWeight: 0,
      totalAmount: 0,
      totalCarbonPoint: score,
      finishTime: now as any,
    });

    if (score > 0) {
      await manager
        .createQueryBuilder()
        .update(UserInfoEntity)
        .set({
          carbonBalance: () => `carbonBalance + ${score}`,
        })
        .where('unionid = :unionid', { unionid })
        .execute();

      await manager.save(RecycleTransactionEntity, {
        userId: unionid,
        departmentId: user.departmentId,
        type: '收入',
        amount: score,
        sourceType: '签到',
        remark: `打卡获得碳积分`,
        orderId: orderNo,
      });
    }

    return {
      orderNo,
      orderId: order.id,
      score,
      nickName: user.nickName,
      unionid,
    };
  }

  /**
   * 回收品类列表（全部启用品类，按类别分组展示）
   */
  async itemList(_sorterId?: string) {
    const list = await this.recycleItemEntity.find({
      where: { status: 0 },
      order: { id: 'ASC' },
    });
    if (list.length) {
      return list;
    }
    return this.recycleItemEntity.find({
      order: { id: 'ASC' },
    });
  }

  /**
   * 保存现场/预约回收清单
   */
  @CoolTransaction()
  async saveOrder(
    param: {
      sorterId: string;
      unionid: string;
      appointmentId?: number;
      items: any[];
    },
    queryRunner?: QueryRunner
  ) {
    if (!queryRunner) {
      throw new CoolCommException('事务启动失败');
    }
    const manager = queryRunner.manager;
    const unionid = String(param.unionid || '').trim();
    const sorter = await this.getSorter(param.sorterId);
    const user = await manager.findOne(UserInfoEntity, {
      where: { unionid },
    });
    if (!user || user.status !== 1) {
      throw new CoolCommException('该用户不是平台用户');
    }

    const items = Array.isArray(param.items) ? param.items : [];
    if (!items.length) {
      throw new CoolCommException('请添加回收清单');
    }

    let appointment: RecycleAppointmentEntity = null;
    if (param.appointmentId) {
      appointment = await manager.findOne(RecycleAppointmentEntity, {
        where: { id: Number(param.appointmentId) },
      });
      if (!appointment) {
        throw new CoolCommException('预约单不存在');
      }
      if (appointment.status === '已完成') {
        throw new CoolCommException('该预约已完成');
      }
      if (appointment.status === '已取消') {
        throw new CoolCommException('该预约已取消');
      }
      if (appointment.campusUserId && appointment.campusUserId !== unionid) {
        throw new CoolCommException('回收码与预约单用户不一致');
      }
    }

    const itemRows = [];
    let totalWeight = 0;
    let totalAmount = 0;
    let totalCarbonPoint = 0;

    for (const row of items) {
      const catalog = await manager.findOne(RecycleItemEntity, {
        where: { itemId: String(row.itemId) },
      });
      if (!catalog) {
        throw new CoolCommException(`回收品类不存在：${row.itemId || ''}`);
      }
      const weight = Number(row.weight);
      if (!weight || weight <= 0) {
        throw new CoolCommException(`请填写${catalog.itemName}的计量`);
      }
      const unitPrice = Number(catalog.price || 0);
      const unitCarbon = Number(catalog.carbonPoint || 0);
      const amount = Number((weight * unitPrice).toFixed(2));
      const carbonPoint = Number((weight * unitCarbon).toFixed(2));
      itemRows.push({
        itemId: catalog.itemId,
        itemName: catalog.itemName,
        category: catalog.category,
        weight,
        unitPrice,
        amount,
        carbonPoint,
      });
      totalWeight += weight;
      totalAmount += amount;
      totalCarbonPoint += carbonPoint;
    }

    totalWeight = Number(totalWeight.toFixed(2));
    totalAmount = Number(totalAmount.toFixed(2));
    totalCarbonPoint = Number(totalCarbonPoint.toFixed(2));

    const orderNo = this.genOrderNo(appointment ? 'YY' : 'XC');
    const now = moment().format('YYYY-MM-DD HH:mm:ss');
    const order = await manager.save(RecycleOrderEntity, {
      orderNo,
      orderType: appointment ? '预约' : '现场',
      campusUserId: unionid,
      departmentId: user.departmentId || sorter.departmentId,
      siteId: sorter.workSiteId,
      sorterId: sorter.businessId,
      appointmentId: appointment ? appointment.id : null,
      status: '已完成',
      totalWeight,
      totalAmount,
      totalCarbonPoint,
      finishTime: now as any,
    });

    await manager.save(
      RecycleOrderItemEntity,
      itemRows.map(item => ({
        ...item,
        orderNo,
      }))
    );

    if (totalCarbonPoint > 0) {
      await manager
        .createQueryBuilder()
        .update(UserInfoEntity)
        .set({
          carbonBalance: () => `carbonBalance + ${totalCarbonPoint}`,
        })
        .where('unionid = :unionid', { unionid })
        .execute();

      await manager.save(RecycleTransactionEntity, {
        userId: unionid,
        departmentId: user.departmentId,
        type: '收入',
        amount: totalCarbonPoint,
        sourceType: '回收',
        remark: `回收订单 ${orderNo} 获得碳积分`,
        orderId: orderNo,
      });
    }

    if (appointment) {
      await manager.update(RecycleAppointmentEntity, appointment.id, {
        status: '已完成',
        sorterId: sorter.businessId,
        recycleOrderId: orderNo,
      });
      await manager.save(RecycleAppointmentLogEntity, {
        appointmentId: appointment.id,
        action: '完成',
        operatorType: '分拣员',
        operatorId: sorter.id,
        remark: `上门回收完成，订单 ${orderNo}`,
      });
    }

    return {
      orderNo,
      orderId: order.id,
      totalWeight,
      totalAmount,
      totalCarbonPoint,
    };
  }

  /**
   * 预约列表
   */
  async appointmentPage(query: any) {
    const { sorterId, status, page = 1, size = 10, keyWord, pool } = query || {};
    const sorter = await this.getSorter(sorterId);
    const find = this.recycleAppointmentEntity
      .createQueryBuilder('a')
      .select([
        'a.*',
        'b.nickName AS campusUserName',
        'c.businessName AS sorterName',
      ])
      .leftJoin(UserInfoEntity, 'b', 'a.campusUserId = b.unionid')
      .leftJoin(BasicdataSorterEntity, 'c', 'a.sorterId = c.businessId');

    if (sorter.departmentId) {
      find.andWhere(
        '(CAST(a.departmentId AS CHAR) = :deptId OR a.departmentId IS NULL)',
        { deptId: String(sorter.departmentId) }
      );
    }
    if (pool === 'new') {
      find.andWhere('a.status IN (:...newSt)', {
        newSt: ['新增', '待审核', '待接单', '未知'],
      });
      find.andWhere(
        "(a.sorterId IS NULL OR CAST(a.sorterId AS CHAR) = '' OR CAST(a.sorterId AS CHAR) = '0')"
      );
    } else if (pool === 'mine') {
      find.andWhere('a.sorterId = :sid', { sid: sorter.businessId });
      find.andWhere('a.status NOT IN (:...done)', {
        done: ['已完成', '已取消'],
      });
    } else if (status) {
      find.andWhere('a.status = :status', { status });
    }
    if (keyWord) {
      find.andWhere(
        '(a.appointmentNo LIKE :kw OR a.contactName LIKE :kw OR a.contactPhone LIKE :kw OR a.address LIKE :kw)',
        { kw: `%${keyWord}%` }
      );
    }

    find.orderBy('a.appointmentDate', 'DESC');
    find.addOrderBy('a.id', 'DESC');
    return this.entityRenderPage(find, { ...query, page, size }, false);
  }

  /**
   * 领取预约单到分拣员名下
   */
  async claimAppointment(param: { id: number; sorterId: string }) {
    const sorter = await this.getSorter(param.sorterId);
    const appointment = await this.recycleAppointmentEntity.findOneBy({
      id: Number(param.id),
    });
    if (!appointment) {
      throw new CoolCommException('预约单不存在');
    }
    if (appointment.status === '已完成') {
      throw new CoolCommException('该预约已完成');
    }
    if (appointment.status === '已取消') {
      throw new CoolCommException('该预约已取消');
    }
    if (
      appointment.sorterId &&
      String(appointment.sorterId) !== '0' &&
      appointment.sorterId !== sorter.businessId
    ) {
      throw new CoolCommException('该预约已被其他分拣员领取');
    }
    await this.recycleAppointmentEntity.update(appointment.id, {
      sorterId: sorter.businessId,
    });
    await this.recycleAppointmentLogEntity.save({
      appointmentId: appointment.id,
      action: '接单',
      operatorType: '分拣员',
      operatorId: sorter.id,
      remark: '分拣员领取预约单',
    });
    return this.recycleAppointmentEntity.findOneBy({ id: appointment.id });
  }

  /**
   * 确认预约
   */
  @CoolTransaction()
  async confirmAppointment(
    param: { id: number; sorterId: string },
    queryRunner?: QueryRunner
  ) {
    if (!queryRunner) {
      throw new CoolCommException('事务启动失败');
    }
    const manager = queryRunner.manager;
    const sorter = await this.getSorter(param.sorterId);
    const appointment = await manager.findOne(RecycleAppointmentEntity, {
      where: { id: Number(param.id) },
    });
    if (!appointment) {
      throw new CoolCommException('预约单不存在');
    }
    if (appointment.status === '已完成') {
      throw new CoolCommException('该预约已完成');
    }
    if (appointment.status === '已取消') {
      throw new CoolCommException('该预约已取消');
    }
    if (appointment.status !== '已确认') {
      await manager.update(RecycleAppointmentEntity, appointment.id, {
        status: '已确认',
        sorterId: sorter.businessId,
      });
      await manager.save(RecycleAppointmentLogEntity, {
        appointmentId: appointment.id,
        action: '确认',
        operatorType: '分拣员',
        operatorId: sorter.id,
        remark: '分拣员确认预约',
      });
    }
    return await manager.findOne(RecycleAppointmentEntity, {
      where: { id: appointment.id },
    });
  }

  /**
   * 扫描预约单
   */
  async scanAppointment(appointmentNo: string, sorterId: string) {
    await this.getSorter(sorterId);
    const no = String(appointmentNo || '').trim();
    if (!no) {
      throw new CoolCommException('请扫描有效的预约单');
    }
    const appointment = await this.recycleAppointmentEntity.findOneBy({
      appointmentNo: no,
    }) || (/^\d+$/.test(no)
      ? await this.recycleAppointmentEntity.findOneBy({ id: Number(no) })
      : null);
    if (!appointment) {
      throw new CoolCommException('预约单不存在');
    }
    if (appointment.status === '已取消') {
      throw new CoolCommException('该预约已取消');
    }
    if (appointment.status === '已完成') {
      throw new CoolCommException('该预约已完成');
    }
    const user = appointment.campusUserId
      ? await this.checkUser(appointment.campusUserId)
      : null;
    return {
      ...appointment,
      campusUser: user,
    };
  }

  /**
   * 生成订单编号
   */
  private genOrderNo(prefix: string) {
    const rand = Math.floor(Math.random() * 90 + 10);
    return `${prefix}${moment().format('YYYYMMDDHHmmssSSS')}${rand}`;
  }
}
