import { DataSource, Repository } from 'typeorm';
import { UserEntityMt } from '@d8d/core-module-mt/user-module-mt';
import { FileServiceMt } from '@d8d/core-module-mt/file-module-mt';
import { SystemConfigServiceMt } from '@d8d/core-module-mt/system-config-module-mt';
import { JWTUtil, redisUtil } from '@d8d/shared-utils';
import axios from 'axios';
import process from 'node:process'
import { log } from 'node:console';
import { nullable } from 'zod/mini';

export class MiniAuthService {
  private userRepository: Repository<UserEntityMt>;
  private fileService: FileServiceMt;
  private systemConfigService: SystemConfigServiceMt;
  private dataSource: DataSource;

  constructor(dataSource: DataSource) {
    this.userRepository = dataSource.getRepository(UserEntityMt);
    this.fileService = new FileServiceMt(dataSource);
    this.systemConfigService = new SystemConfigServiceMt(dataSource);
    this.dataSource = dataSource;
  }

  async miniLogin(code: string, tenantId?: number): Promise<{ token: string; user: UserEntityMt; isNewUser: boolean }> {
    // 1. 通过code获取openid和session_key
    const openidInfo = await this.getOpenIdByCode(code, tenantId);

    // 2. 查找或创建用户
    let user = await this.userRepository.findOne({
      where: { openid: openidInfo.openid }
    });

    let isNewUser = false;

    if (!user) {
      // 自动注册新用户
      user = await this.createMiniUser(openidInfo, tenantId);
      isNewUser = true;
    }

    // 3. 保存sessionKey到Redis
    await redisUtil.setSessionKey(user.id, openidInfo.session_key);

    // 4. 生成token
    const token = this.generateToken(user);

    return { token, user, isNewUser };
  }

  async updateUserProfile(userId: number, profile: { nickname?: string; avatarUrl?: string }): Promise<UserEntityMt> {
    const user = await this.userRepository.findOne({
      where: { id: userId },
      relations: ['avatarFile']
    });

    if (!user) throw new Error('用户不存在');

    if (profile.nickname) user.nickname = profile.nickname;

    // 处理头像：如果用户没有头像且提供了小程序头像URL，则下载保存
    if (profile.avatarUrl && !user.avatarFileId) {
      try {
        const avatarFileId = await this.downloadAndSaveAvatar(profile.avatarUrl, userId);
        if (avatarFileId) {
          user.avatarFileId = avatarFileId;
        }
      } catch (error) {
        // 头像下载失败不影响主要功能
        console.error('头像下载失败:', error);
      }
    }

    return await this.userRepository.save(user);
  }

  private async getOpenIdByCode(code: string, tenantId?: number): Promise<{ openid: string; unionid?: string; session_key: string }> {
    // 优先从系统配置获取，如果配置不存在则回退到环境变量
    let appId: string | null = null;
    let appSecret: string | null = null;

    if (tenantId !== undefined) {
      // 从系统配置获取
      const configKeys = ['wx.mini.app.id', 'wx.mini.app.secret'];
      const configs = await this.systemConfigService.getConfigsByKeys(configKeys, tenantId);
      appId = configs['wx.mini.app.id'];
      appSecret = configs['wx.mini.app.secret'];
    }

    // 如果系统配置中没有找到，回退到环境变量
    if (!appId) {
      appId = process.env.WX_MINI_APP_ID || null;
    }
    if (!appSecret) {
      appSecret = process.env.WX_MINI_APP_SECRET || null;
    }

    if (!appId || !appSecret) {
      throw new Error('微信小程序配置缺失');
    }

    const url = `https://api.weixin.qq.com/sns/jscode2session?appid=${appId}&secret=${appSecret}&js_code=${code}&grant_type=authorization_code`;

    try {
      const response = await axios.get(url, { timeout: 10000 });

      if (response.data.errcode) {
        throw new Error(`微信API错误: ${response.data.errmsg}`);
      }

      return {
        openid: response.data.openid,
        unionid: response.data.unionid,
        session_key: response.data.session_key
      };
    } catch (error) {
      if (axios.isAxiosError(error)) {
        throw new Error('微信服务器连接失败');
      }
      throw error;
    }
  }

  private async createMiniUser(openidInfo: { openid: string; unionid?: string }, tenantId?: number): Promise<UserEntityMt> {
    const user = this.userRepository.create({
      tenantId: tenantId || 1, // 默认租户ID为1，如果未提供
      username: `wx_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`,
      password: '', // 小程序用户不需要密码
      openid: openidInfo.openid,
      unionid: openidInfo.unionid,
      nickname: '微信用户',
      registrationSource: 'miniapp',
      isDisabled: 0,
      isDeleted: 0
    });

    return await this.userRepository.save(user);
  }

  private async downloadAndSaveAvatar(avatarUrl: string, userId: number): Promise<number | null> {
    try {
      const result = await this.fileService.downloadAndSaveFromUrl(
        avatarUrl,
        {
          uploadUserId: userId,
          customPath: `avatars/`,
          mimeType: 'image/jpeg'
        },
        { timeout: 10000 }
      );

      return result.file.id;
    } catch (error) {
      console.error('下载保存头像失败:', error);
      return null;
    }
  }

  private generateToken(user: UserEntityMt): string {
    return JWTUtil.generateToken({
      id: user.id,
      username: user.username,
      roles: user.roles,
      openid: user.openid || undefined
    });
  }

  /**
   * 解密小程序加密的手机号
   */
  async decryptPhoneNumber(encryptedData: string, iv: string, sessionKey: string): Promise<string> {

    // 参数验证
    if (!encryptedData || !iv || !sessionKey) {
      throw { code: 400, message: '加密数据或初始向量不能为空' };
    }

    try {
      // 使用Node.js内置crypto模块进行AES-128-CBC解密
      // 微信小程序手机号解密算法：AES-128-CBC，PKCS#7填充
      const crypto = await import('node:crypto');

      // 创建解密器
      const decipher = crypto.createDecipheriv(
        'aes-128-cbc',
        Buffer.from(sessionKey, 'base64'),
        Buffer.from(iv, 'base64')
      );

      // 设置自动PKCS#7填充
      decipher.setAutoPadding(true);

      // 解密数据
      let decrypted = decipher.update(Buffer.from(encryptedData, 'base64'));
      decrypted = Buffer.concat([decrypted, decipher.final()]);

      // 解析解密后的JSON数据
      const decryptedStr = decrypted.toString('utf8');
      const phoneData = JSON.parse(decryptedStr);

      // 验证解密结果
      if (!phoneData.phoneNumber || typeof phoneData.phoneNumber !== 'string') {
        throw new Error('解密数据格式不正确');
      }

      return phoneData.phoneNumber;

    } catch (error) {
      console.error('手机号解密失败:', error);

      // 根据错误类型返回相应的错误信息
      if (error instanceof SyntaxError) {
        throw { code: 400, message: '解密数据格式错误' };
      } else if (error instanceof Error && error.message?.includes('wrong final block length')) {
        throw { code: 400, message: '解密数据长度不正确' };
      } else if (error instanceof Error && error.message?.includes('bad decrypt')) {
        throw { code: 400, message: '解密失败，请检查sessionKey是否正确' };
      } else {
        const errorMessage = error instanceof Error ? error.message : '未知错误';
        throw { code: 400, message: '手机号解密失败: ' + errorMessage };
      }
    }
  }



  /**
   * 发送微信模板消息
   */
  async sendTemplateMessage(params: {
    openid: string;
    templateId: string;
    page?: string;
    data: Record<string, { value: string }>;
    miniprogramState?: 'developer' | 'trial' | 'formal';
    tenantId?: number;
  }): Promise<any> {
    const { openid, templateId, page, data, miniprogramState = 'formal', tenantId } = params;

    // 构建模板消息请求数据
    const templateMessageData = {
      touser: openid,
      template_id: templateId,
      page: page || 'pages/index/index',
      data: data,
      miniprogram_state: miniprogramState
    };

    const accessToken = await this.getWxAccessToken(tenantId);

    // 调用微信模板消息API
    const url = `https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=${accessToken}`;

    try {
      const response = await axios.post(url, templateMessageData, {
        timeout: 10000,
        headers: {
          'Content-Type': 'application/json'
        }
      });

      if (response.data.errcode && response.data.errcode !== 0) {
        throw new Error(`微信模板消息发送失败: ${response.data.errmsg} (errcode: ${response.data.errcode})`);
      }

      console.debug('微信模板消息发送成功:', response.data);
      return response.data;

    } catch (error) {
      if (axios.isAxiosError(error)) {
        throw new Error(`微信服务器连接失败: ${error.message}`);
      }
      throw error;
    }
  }
  
  /**
   * 根据订单号查询微信支付订单信息
   */
  private async getWechatOrderInfo(orderNo: string, tenantId?: number): Promise<{
    outTradeNo: string;
    wechatTransactionId?: string;
  }> {
    try {
      // 1. 先通过订单号查询订单，获取订单ID
      const orderRepository = this.dataSource.getRepository('OrderMt');
      const order = await orderRepository.findOne({
        where: {
          orderNo: orderNo,
          ...(tenantId !== undefined ? { tenantId } : {})
        },
        select: ['id'] // 只选择id字段
      });

      if (!order) {
        throw new Error(`订单不存在: ${orderNo}`);
      }

      // 2. 通过订单ID查询支付记录
      const paymentRepository = this.dataSource.getRepository('PaymentMtEntity');
      const payment = await paymentRepository.findOne({
        where: {
          externalOrderId: order.id,
          ...(tenantId !== undefined ? { tenantId } : {})
        }
      });

      if (!payment) {
        throw new Error(`支付记录不存在，订单号: ${orderNo}, 订单ID: ${order.id}`);
      }

      if (!payment.outTradeNo) {
        throw new Error(`支付记录 ${orderNo} 没有微信支付商户订单号`);
      }

      return {
        outTradeNo: payment.outTradeNo,
        wechatTransactionId: payment.wechatTransactionId
      };
    } catch (error) {
      console.error(`查询微信支付订单信息失败:`, {
        orderNo,
        tenantId,
        error: error instanceof Error ? error.message : '未知错误'
      });
      throw error;
    }
  }

  /**
   * 根据订单ID查询用户openid
   */
  private async getOpenidByOrderId(orderId: string, tenantId?: number): Promise<string> {
    try {
      // 动态获取订单仓库，避免循环依赖
      // 注意：这里使用 any 类型来避免类型导入问题
      const orderRepository = this.dataSource.getRepository('OrderMt');

      // 查询订单，包含用户关联关系
      const order = await orderRepository.findOne({
        where: { orderNo: orderId, ...(tenantId !== undefined ? { tenantId } : {}) },
        relations: ['user']
      });

      if (!order) {
        throw new Error(`订单不存在: ${orderId}`);
      }

      if (!order.user) {
        throw new Error(`订单 ${orderId} 没有关联的用户信息`);
      }

      if (!order.user.openid) {
        throw new Error(`订单 ${orderId} 关联的用户没有openid`);
      }

      return order.user.openid;
    } catch (error) {
      console.error(`查询订单openid失败:`, {
        orderId,
        tenantId,
        error: error instanceof Error ? error.message : '未知错误'
      });
      throw error;
    }
  }

  /**
   * 发货信息录入
   * 微信小程序发货信息录入API：https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order-shipping/order-shipping.html
   */
  async uploadShippingInfo(params: {
    orderId: string; // 小程序订单ID
    deliveryType: number; // 发货方式：1-物流快递, 2-同城配送, 3-虚拟发货, 4-用户自提
    expressInfo?: {
      deliveryId: string; // 快递公司ID，通过getCompanyList获取
      waybillId: string; // 快递单号
    };
    localDeliveryInfo?: {
      deliveryName?: string; // 配送员姓名
      deliveryPhone?: string; // 配送员手机号
    };
    isAllDelivered?: boolean; // 是否全部发货完成，默认true
    itemDesc?: string; // 商品描述，最多110个字
    tenantId?: number;
  }): Promise<any> {
    const { orderId, deliveryType, expressInfo, localDeliveryInfo, isAllDelivered = true, itemDesc, tenantId } = params;

    // 参数验证
    if (!orderId) {
      throw new Error('订单ID不能为空');
    }

    const accessToken = await this.getWxAccessToken(tenantId);

    // 获取商户号（mchid）
    let mchid: string | null = null;
    if (tenantId !== undefined) {
      const configKeys = ['wx.payment.merchant.id'];
      const configs = await this.systemConfigService.getConfigsByKeys(configKeys, tenantId);
      mchid = configs['wx.payment.merchant.id'];
    }

    // 如果系统配置中没有找到，回退到环境变量
    if (!mchid) {
      mchid = process.env.WECHAT_MERCHANT_ID || null;
    }

    if (!mchid) {
      throw new Error('微信商户号配置缺失，无法使用小程序订单号发货');
    }

    // 查询支付记录，获取微信支付订单号
    const wechatOrderInfo = await this.getWechatOrderInfo(orderId, tenantId);

    // 查询订单对应的用户openid
    const openid = await this.getOpenidByOrderId(orderId, tenantId);

    const shippingData: any = {
      order_key: {
        order_number_type: 1, // 1-小程序订单号
        out_trade_no: wechatOrderInfo.outTradeNo, // 使用微信支付商户订单号
        mchid: mchid // 添加商户号字段
      },
      logistics_type: deliveryType,
      delivery_mode: isAllDelivered ? 1 : 2,
      shipping_list: [
        {
          item_desc: itemDesc || `订单${orderId}`
        }
      ],
      upload_time: new Date().toISOString().replace('Z', '+08:00'), // RFC 3339 格式，使用东八区时间
      payer: {
        openid: openid // 支付方openid，从订单获取用户openid
      }
    };

    // 根据发货方式添加不同的信息
    switch (deliveryType) {
      case 1: // 物流快递
        if (!expressInfo?.deliveryId || !expressInfo?.waybillId) {
          throw new Error('快递发货需要提供快递公司ID和运单号');
        }
        shippingData.shipping_list = [
          {
            tracking_no: expressInfo.waybillId,
            express_company: expressInfo.deliveryId,
            item_desc: itemDesc || `订单${orderId}`, // 使用前端传递的商品描述，默认为订单ID
          }
        ];
        break;

      case 2: // 同城配送
      case 3: // 虚拟发货
      case 4: // 用户自提
        // 无需物流，不需要额外信息
        break;

      default:
        throw new Error(`不支持的发货方式: ${deliveryType}`);
    }

    const url = `https://api.weixin.qq.com/wxa/sec/order/upload_shipping_info?access_token=${accessToken}`;

    try {
      const response = await axios.post(url, shippingData, {
        timeout: 10000,
        headers: {
          'Content-Type': 'application/json'
        }
      });

      if (response.data.errcode && response.data.errcode !== 0) {
        const errorMsg = this.getShippingErrorMsg(response.data.errcode, response.data.errmsg);
        console.error(`微信发货失败: ${errorMsg}`, {
          orderId,
          deliveryType,
          errcode: response.data.errcode,
          errmsg: response.data.errmsg
        });
        throw new Error(errorMsg);
      }

      console.debug('微信发货成功:', {
        orderId,
        deliveryType,
        response: response.data
      });
      return response.data;

    } catch (error) {
      console.error('发货信息录入异常:', {
        orderId,
        deliveryType,
        error: error instanceof Error ? error.message : '未知错误',
        stack: error instanceof Error ? error.stack : undefined
      });

      if (axios.isAxiosError(error)) {
        if (error.code === 'ECONNABORTED') {
          throw new Error('微信服务器连接超时，请稍后重试');
        } else if (error.code === 'ENOTFOUND') {
          throw new Error('无法连接到微信服务器，请检查网络');
        } else {
          throw new Error(`微信服务器连接失败: ${error.message}`);
        }
      } else if (error instanceof Error) {
        // 如果是我们抛出的错误，直接抛出
        throw error;
      } else {
        throw new Error('发货信息录入失败，请稍后重试');
      }
    }
  }


  async getCompanyList(tenantId?: number): Promise<any> {
    
    const accessToken = await this.getWxAccessToken(tenantId);
 
    const url = `https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/get_delivery_list?access_token=${accessToken}`;

    try {
      const response = await axios.post(url, {}, {
        timeout: 10000,
        headers: {
          'Content-Type': 'application/json'
        }
      });

      if (response.data.errcode && response.data.errcode !== 0) {
        throw new Error(`获取快递公司列表失败: ${response.data.errmsg} (errcode: ${response.data.errcode})`);
      }

      console.debug('获取快递公司列表成功:', response.data);

      // 微信API返回delivery_list字段，但路由期望company_list字段
      // 确保返回正确的数据结构
      const companyList = response.data.delivery_list || [];

      return {
        company_list: companyList
      };

    } catch (error) {
      if (axios.isAxiosError(error)) {
        throw new Error(`微信服务器连接失败: ${error.message}`);
      }
      throw error;
    }
  }

  async getIsTradeManaged(tenantId?: number): Promise<any> {

    const accessToken = await this.getWxAccessToken(tenantId);

    const url = `https://api.weixin.qq.com/wxa/sec/order/is_trade_managed?access_token=${accessToken}`;


    // 从系统配置获取appid
    let appId: string | null = null;
    const configKeys = ['wx.mini.app.id', 'wx.mini.app.secret'];

    if (tenantId !== undefined) {
      const configs = await this.systemConfigService.getConfigsByKeys(configKeys, tenantId);
      appId = configs['wx.mini.app.id'];
    }

    // 如果系统配置中没有找到，回退到环境变量
    if (!appId) {
      appId = process.env.WX_MINI_APP_ID || null;
    }

    // 检查appid是否存在
    if (!appId) {
      throw new Error('微信小程序appid配置缺失');
    }

    try {
      // 微信API要求POST方法，并且需要在请求体中传递appid参数
      const requestBody = {
        appid: appId
      };

      const response = await axios.post(url, requestBody, {
        timeout: 10000,
        headers: {
          'Content-Type': 'application/json'
        }
      });

      if (response.data.errcode && response.data.errcode !== 0) {
        // 处理特定的错误码
        if (response.data.errcode === 48001) {
          throw new Error('API功能未授权，请确认小程序已开通微信小店功能并申请相应权限');
        }
        throw new Error(`检查交易管理状态失败: ${response.data.errmsg} (errcode: ${response.data.errcode})`);
      }

      console.debug('检查交易管理状态成功:', response.data);
      return response.data;

    } catch (error) {
      if (axios.isAxiosError(error)) {
        throw new Error(`微信服务器连接失败: ${error.message}`);
      }
      throw error;
    }
  }


  // async getCompanyList(tenantId?: number): Promise<any> {
  //   // 使用内置的快递公司列表，避免微信API权限问题
  //   const builtInDeliveryCompanies = [
  //     { delivery_id: 'SF', delivery_name: '顺丰速运' },
  //     { delivery_id: 'STO', delivery_name: '申通快递' },
  //     { delivery_id: 'YTO', delivery_name: '圆通速递' },
  //     { delivery_id: 'YD', delivery_name: '韵达快递' },
  //     { delivery_id: 'ZTO', delivery_name: '中通快递' },
  //     { delivery_id: 'HTKY', delivery_name: '百世快递' },
  //     { delivery_id: 'YZPY', delivery_name: '邮政快递' },
  //     { delivery_id: 'JD', delivery_name: '京东物流' },
  //     { delivery_id: 'EMS', delivery_name: 'EMS' },
  //     { delivery_id: 'TTKDEX', delivery_name: '天天快递' },
  //     { delivery_id: 'DBL', delivery_name: '德邦物流' },
  //     { delivery_id: 'ZJS', delivery_name: '宅急送' }
  //   ];
  
  //   console.debug('返回内置快递公司列表，共', builtInDeliveryCompanies.length, '家');
    
  //   return {
  //     company_list: builtInDeliveryCompanies
  //   };
  // }



  /**
   * 查询发货状态
   * 微信小程序发货状态查询API
   */
  async getShippingStatus(params: {
    orderId: string; // 小程序订单ID
    tenantId?: number;
  }): Promise<{
    orderId: string;
    shippingStatus: number; // 发货状态：0-未发货，1-已发货，2-已签收，3-已取消
    deliveryMode?: string; // 发货方式
    expressInfo?: {
      deliveryId: string;
      deliveryName: string;
      waybillId: string;
    };
    localDeliveryInfo?: {
      deliveryName: string;
      deliveryPhone: string;
    };
    shippingTime?: string; // 发货时间
    estimatedDeliveryTime?: string; // 预计送达时间
    actualDeliveryTime?: string; // 实际送达时间
  }> {
    const { orderId, tenantId } = params;

    if (!orderId) {
      throw new Error('订单ID不能为空');
    }

    const accessToken = await this.getWxAccessToken(tenantId);

    const queryData = {
      order_key: {
        order_number_type: 1, // 1-小程序订单号
        out_trade_no: orderId
      }
    };

    const url = `https://api.weixin.qq.com/wxa/sec/order/get_shipping_info?access_token=${accessToken}`;

    try {
      const response = await axios.post(url, queryData, {
        timeout: 10000,
        headers: {
          'Content-Type': 'application/json'
        }
      });

      if (response.data.errcode && response.data.errcode !== 0) {
        const errorMsg = this.getShippingErrorMsg(response.data.errcode, response.data.errmsg);
        console.error(`查询发货状态失败: ${errorMsg}`, {
          orderId,
          errcode: response.data.errcode,
          errmsg: response.data.errmsg
        });
        throw new Error(errorMsg);
      }

      const shippingInfo = response.data.shipping_info;
      const result: {
        orderId: string;
        shippingStatus: number;
        deliveryMode?: string;
        expressInfo?: {
          deliveryId: string;
          deliveryName: string;
          waybillId: string;
        };
        localDeliveryInfo?: {
          deliveryName: string;
          deliveryPhone: string;
        };
        shippingTime?: string;
        estimatedDeliveryTime?: string;
        actualDeliveryTime?: string;
      } = {
        orderId,
        shippingStatus: shippingInfo?.logistics_status || 0,
        deliveryMode: this.getDeliveryModeFromLogisticsType(shippingInfo?.logistics_type),
        shippingTime: shippingInfo?.shipping_time,
        estimatedDeliveryTime: shippingInfo?.estimated_delivery_time,
        actualDeliveryTime: shippingInfo?.actual_delivery_time
      };

      // 处理快递信息
      if (shippingInfo?.delivery_list?.length > 0) {
        const delivery = shippingInfo.delivery_list[0];
        if (delivery.delivery_id) {
          result.expressInfo = {
            deliveryId: delivery.delivery_id,
            deliveryName: delivery.delivery_name || this.getDeliveryCompanyName(delivery.delivery_id),
            waybillId: delivery.waybill_id
          };
        } else if (delivery.delivery_name) {
          result.localDeliveryInfo = {
            deliveryName: delivery.delivery_name,
            deliveryPhone: delivery.delivery_phone
          };
        }
      }

      console.debug('发货状态查询成功:', {
        orderId,
        shippingStatus: result.shippingStatus,
        deliveryMode: result.deliveryMode
      });

      return result;

    } catch (error) {
      console.error('发货状态查询异常:', {
        orderId,
        error: error instanceof Error ? error.message : '未知错误'
      });

      if (axios.isAxiosError(error)) {
        throw new Error(`查询发货状态失败: ${error.message}`);
      }
      throw error;
    }
  }



  /**
   * 根据发货方式获取物流类型编码
   * 微信API要求：0-无需物流，1-快递，2-同城配送
   */
  private getLogisticsType(deliveryMode: 'express' | 'no_logistics' | 'local_delivery'): number {
    switch (deliveryMode) {
      case 'no_logistics':
        return 0;
      case 'express':
        return 1;
      case 'local_delivery':
        return 2;
      default:
        throw new Error(`不支持的发货方式: ${deliveryMode}`);
    }
  }

  /**
   * 获取发货错误信息
   * 根据微信API错误码返回友好的错误信息
   */
  private getShippingErrorMsg(errcode: number, errmsg: string): string {
    const errorMap: Record<number, string> = {
      40001: 'access_token无效或已过期',
      40003: '非法的openid',
      40013: 'appid无效',
      40029: 'code无效',
      40050: '不支持的物流类型',
      40051: '订单不存在',
      40052: '订单状态不允许发货',
      40053: '快递公司ID无效',
      40054: '运单号格式错误',
      40055: '同城配送信息不完整',
      40056: '订单已发货，不能重复发货',
      40057: '订单已取消，不能发货',
      40058: '订单已退款，不能发货',
      40059: '订单已关闭，不能发货',
      41001: '缺少access_token参数',
      41002: '缺少订单ID参数',
      41003: '缺少物流类型参数',
      41004: '缺少快递公司ID参数',
      41005: '缺少运单号参数',
      41006: '缺少同城配送员姓名',
      41007: '缺少同城配送员手机号',
      42001: 'access_token已过期',
      43001: '需要GET请求',
      43002: '需要POST请求',
      43003: '需要HTTPS请求',
      44001: '多媒体文件为空',
      45001: '多媒体文件大小超过限制',
      45002: '消息内容超过限制',
      45003: '标题字段超过限制',
      45004: '描述字段超过限制',
      45005: '链接字段超过限制',
      45006: '图片链接字段超过限制',
      45007: '语音播放时间超过限制',
      45008: '图文消息超过限制',
      45009: '接口调用超过限制',
      45010: '创建菜单个数超过限制',
      45011: 'API调用太频繁，请稍候再试',
      45015: '回复时间超过限制',
      45016: '系统分组，不允许修改',
      45017: '分组名字过长',
      45018: '分组数量超过上限',
      46001: '不存在媒体数据',
      46002: '不存在的菜单版本',
      46003: '不存在的菜单数据',
      46004: '不存在的用户',
      47001: '解析JSON/XML内容错误',
      48001: 'api功能未授权',
      50001: '用户未授权该api',
      50002: '用户受限，可能是违规后接口被封禁'
    };

    const friendlyMsg = errorMap[errcode] || errmsg;
    return `微信发货失败: ${friendlyMsg} (错误码: ${errcode})`;
  }

  /**
   * 根据物流类型编码获取发货方式
   */
  private getDeliveryModeFromLogisticsType(logisticsType?: number): string {
    switch (logisticsType) {
      case 0:
        return 'no_logistics';
      case 1:
        return 'express';
      case 2:
        return 'local_delivery';
      default:
        return 'unknown';
    }
  }

  /**
   * 根据快递公司ID获取公司名称
   */
  private getDeliveryCompanyName(deliveryId: string): string {
    const deliveryMap: Record<string, string> = {
      'SF': '顺丰速运',
      'STO': '申通快递',
      'YTO': '圆通速递',
      'YD': '韵达快递',
      'ZTO': '中通快递',
      'HTKY': '百世快递',
      'YZPY': '邮政快递',
      'JD': '京东物流',
      'YUNDA': '韵达快递',
      'EMS': 'EMS',
      'TTKDEX': '天天快递',
      'DBL': '德邦物流',
      'ZJS': '宅急送',
      'QFKD': '全峰快递',
      'UAPEX': '全一快递',
      'CNEX': '佳吉快运',
      'FAST': '快捷快递',
      'POSTB': '邮政小包',
      'GTO': '国通快递',
      'ANE': '安能物流'
    };

    return deliveryMap[deliveryId] || deliveryId;
  }



  /**
   * 快递公司名称到微信小店delivery_id的映射
   * 实际项目中需要从数据库或配置中获取
   */
  private mapDeliveryCompanyToId(companyName: string): string | null {
    // 简单的映射表，实际项目需要完整的映射
    const deliveryMap: Record<string, string> = {
      '顺丰速运': 'SF',
      '申通快递': 'STO',
      '圆通速递': 'YTO',
      '韵达快递': 'YD',
      '中通快递': 'ZTO',
      '百世快递': 'HTKY',
      '邮政快递': 'YZPY',
      '京东物流': 'JD'
    };

    // 查找匹配的快递公司
    for (const [key, value] of Object.entries(deliveryMap)) {
      if (companyName.includes(key)) {
        return value;
      }
    }

    console.warn(`未找到快递公司映射: ${companyName}`);
    return null;
  }


  async getWxAccessToken(tenantId?: number): Promise<string> {
  
    // 获取微信小程序配置
    let appId: string | null = null;
    let appSecret: string | null = null;
 
    if (tenantId !== undefined) {
      // 从系统配置获取
      const configKeys = ['wx.mini.app.id', 'wx.mini.app.secret'];
      try {
        const configs = await this.systemConfigService.getConfigsByKeys(configKeys, tenantId);
        appId = configs['wx.mini.app.id'];
        appSecret = configs['wx.mini.app.secret'];
 
      } catch (error) {
        console.error("获取系统配置失败:", error);
        throw error;
      }
    } else {
      console.debug("tenantId未提供，将使用环境变量");
    }
 
    // 如果系统配置中没有找到，回退到环境变量
    if (!appId) {
      appId = process.env.WX_MINI_APP_ID || null;
    }
    if (!appSecret) {
      appSecret = process.env.WX_MINI_APP_SECRET || null;
    }
 
    if (!appId || !appSecret) {
      throw new Error('微信小程序配置缺失');
    }
 
    // 获取access_token（支持租户隔离）
    const accessToken = await this.getAccessToken(appId, appSecret, tenantId);
    return accessToken;
   }

  /**
   * 获取微信access_token（带缓存机制，支持租户隔离）
   */
  private async getAccessToken(appId: string, appSecret: string, tenantId?: number): Promise<string> {
    // 1. 首先尝试从Redis缓存获取（支持租户隔离）
    const cachedTokenData = await redisUtil.getWechatAccessToken(appId, tenantId);

    if (cachedTokenData) {
      // 检查缓存剩余时间，如果少于60秒则认为即将过期，重新获取
      const remainingSeconds = Math.round((cachedTokenData.expireAt - Date.now()) / 1000);

      if (remainingSeconds > 60) {
        // 剩余时间大于60秒，使用缓存
        console.debug(`使用缓存的微信access_token，appId: ${appId}, 租户ID: ${tenantId || '无'}, 剩余时间: ${remainingSeconds}秒`);
        return cachedTokenData.token;
      } else {
        // 剩余时间不足60秒，认为缓存即将过期，重新获取
        console.debug(`微信access_token缓存即将过期，剩余时间: ${remainingSeconds}秒，重新获取，appId: ${appId}, 租户ID: ${tenantId || '无'}`);
        // 先删除即将过期的缓存
        await redisUtil.deleteWechatAccessToken(appId, tenantId);
      }
    } else {
      console.debug(`缓存中未找到微信access_token，从API获取，appId: ${appId}, 租户ID: ${tenantId || '无'}`);
    }

    // 2. 缓存中没有，调用微信API获取
    // 使用稳定版access_token接口，避免"invalid credential"错误
    const url = `https://api.weixin.qq.com/cgi-bin/stable_token`;
    const requestData = {
      grant_type: 'client_credential',
      appid: appId,
      secret: appSecret,
      force_refresh: false // 不强制刷新，使用缓存
    };

    console.debug(`调用微信稳定版API获取access_token，appId: ${appId}`);

    try {
      const response = await axios.post(url, requestData, {
        timeout: 10000,
        headers: {
          'Content-Type': 'application/json'
        }
      });
      console.debug(`微信稳定版API响应状态: ${response.status}, 数据:`, response.data);

      if (response.data.errcode) {
        console.error(`微信稳定版API返回错误，errcode: ${response.data.errcode}, errmsg: ${response.data.errmsg}`);

        // 如果稳定版接口失败，尝试普通接口作为降级
        if (response.data.errcode === 40001 || response.data.errcode === 41001) {
          console.debug(`稳定版接口失败，尝试普通接口，errcode: ${response.data.errcode}`);
          return await this.getNormalAccessToken(appId, appSecret, tenantId);
        }

        throw new Error(`获取access_token失败: ${response.data.errmsg}`);
      }

      const accessToken = response.data.access_token;
      const expiresIn = response.data.expires_in || 7200; // 微信默认返回7200秒（2小时）
      console.debug(`微信稳定版access_token获取成功，token长度: ${accessToken?.length || 0}, expires_in: ${expiresIn}秒`);

      // 3. 将获取到的access_token存入Redis缓存（支持租户隔离）
      // 设置过期时间比微信返回的expires_in少100秒，确保安全
      const cacheExpiresIn = Math.max(expiresIn - 100, 600); // 最少缓存10分钟
      console.debug(`准备缓存稳定版access_token，过期时间: ${cacheExpiresIn}秒`);
      await redisUtil.setWechatAccessToken(appId, accessToken, cacheExpiresIn, tenantId);

      console.debug(`微信稳定版access_token获取成功并已缓存，appId: ${appId}, 租户ID: ${tenantId || '无'}, 过期时间: ${cacheExpiresIn}秒`);

      return accessToken;

    } catch (error) {
      console.error(`获取微信稳定版access_token异常，appId: ${appId}, 租户ID: ${tenantId || '无'}`, error);
      if (axios.isAxiosError(error)) {
        console.error(`Axios错误，code: ${error.code}, message: ${error.message}`);
        // 网络错误时尝试普通接口
        console.debug(`稳定版接口网络错误，尝试普通接口`);
        return await this.getNormalAccessToken(appId, appSecret, tenantId);
      }
      throw error;
    }
  }

  /**
   * 获取普通版微信access_token（降级方案）
   */
  private async getNormalAccessToken(appId: string, appSecret: string, tenantId?: number): Promise<string> {
    const url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appId}&secret=${appSecret}`;
    console.debug(`调用微信普通版API获取access_token，URL: ${url.replace(appSecret, '***')}`);

    try {
      const response = await axios.get(url, { timeout: 10000 });
      console.debug(`微信普通版API响应状态: ${response.status}, 数据:`, response.data);

      if (response.data.errcode) {
        console.error(`微信普通版API返回错误，errcode: ${response.data.errcode}, errmsg: ${response.data.errmsg}`);
        throw new Error(`获取access_token失败: ${response.data.errmsg}`);
      }

      const accessToken = response.data.access_token;
      const expiresIn = response.data.expires_in || 7200; // 微信默认返回7200秒（2小时）
      console.debug(`微信普通版access_token获取成功，token长度: ${accessToken?.length || 0}, expires_in: ${expiresIn}秒`);

      // 将获取到的access_token存入Redis缓存（支持租户隔离）
      // 设置过期时间比微信返回的expires_in少100秒，确保安全
      const cacheExpiresIn = Math.max(expiresIn - 100, 600); // 最少缓存10分钟
      console.debug(`准备缓存普通版access_token，过期时间: ${cacheExpiresIn}秒`);
      await redisUtil.setWechatAccessToken(appId, accessToken, cacheExpiresIn, tenantId);

      console.debug(`微信普通版access_token获取成功并已缓存，appId: ${appId}, 租户ID: ${tenantId || '无'}, 过期时间: ${cacheExpiresIn}秒`);

      return accessToken;

    } catch (error) {
      console.error(`获取微信普通版access_token异常，appId: ${appId}, 租户ID: ${tenantId || '无'}`, error);
      if (axios.isAxiosError(error)) {
        console.error(`Axios错误，code: ${error.code}, message: ${error.message}`);
        throw new Error('微信服务器连接失败，无法获取access_token');
      }
      throw error;
    }
  }

  /**
   * 强制刷新微信access_token（清除缓存并重新获取，支持租户隔离）
   */
  private async refreshAccessToken(appId: string, appSecret: string, tenantId?: number): Promise<string> {
    console.debug(`强制刷新微信access_token，appId: ${appId}, 租户ID: ${tenantId || '无'}`);

    // 1. 清除缓存（支持租户隔离）
    console.debug(`删除微信access_token缓存，appId: ${appId}, 租户ID: ${tenantId || '无'}`);
    await redisUtil.deleteWechatAccessToken(appId, tenantId);
    console.debug(`微信access_token缓存已删除，appId: ${appId}, 租户ID: ${tenantId || '无'}`);

    // 2. 重新获取（支持租户隔离）
    console.debug(`开始重新获取微信access_token，appId: ${appId}, 租户ID: ${tenantId || '无'}`);
    const token = await this.getAccessToken(appId, appSecret, tenantId);
    console.debug(`微信access_token重新获取完成，appId: ${appId}, 租户ID: ${tenantId || '无'}, 成功: ${!!token}`);
    return token;
  }

  /**
   * 检查微信access_token缓存状态（支持租户隔离）
   */
  private async checkAccessTokenCacheStatus(appId: string, tenantId?: number): Promise<{
    hasCache: boolean;
    ttl: number;
    isValid: boolean;
  }> {
    const tokenData = await redisUtil.getWechatAccessToken(appId, tenantId);
    const hasCache = !!tokenData;

    let ttl = -2; // 默认键不存在
    if (tokenData) {
      ttl = Math.round((tokenData.expireAt - Date.now()) / 1000);
      if (ttl < 0) ttl = 0; // 如果已过期但Redis还没删除，设为0
    }

    return {
      hasCache,
      ttl,
      isValid: hasCache && ttl > 60 // 剩余时间大于60秒认为有效
    };
  }
}