const jwt = require('jsonwebtoken');

// JWT配置
const JWT_SECRET = think.md5('yzx');
const JWT_EXPIRES_IN = 24 * 60 * 60;

// 白名单配置
const WHITE_LIST = [
  '/admin/login',
  '/admin/auth/login',
  '/admin/auth/captcha',
  '/admin/logout',
  '/api/content',
  '/api/mp/login',
  '/common/ocr/idcard',
  '/common/ocr/hmt',
];

module.exports = class extends think.Controller {
  async __before() {
    const path = this.ctx.path;
    // 白名单放行（同时匹配带.html后缀的路径）
    const pathNoSuffix = path.replace(/\.html$/, '');
    if (WHITE_LIST.includes(path) || WHITE_LIST.includes(pathNoSuffix)) {
      return;
    }

    // 后台路由需要验证JWT
    if (path.startsWith('/admin')) {
      const token = this.cookie('admin_token') || this.header('authorization')?.replace('Bearer ', '');

      if (!token) {
        return this.handleUnauthorized();
      }

      try {
        const decoded = jwt.verify(token, JWT_SECRET);
        this.adminUser = decoded;

        if (!this.isAjax()) {
          this.assign('version', think.config('version'));
          await this.loadUserPermissions();
          this.assign('adminUser', this.adminUser || {});
        }
      } catch (err) {
        return this.handleUnauthorized();
      }
    }

    // 小程序API路由验证JWT
    if (path.startsWith('/api/mp/')) {
      const token = this.header('authorization')?.replace('Bearer ', '');
      if (token) {
        try {
          const decoded = jwt.verify(token, JWT_SECRET);
          if (decoded.type === 'mp') {
            this.mpUser = decoded;
          }
        } catch (err) {
          // token无效，mpUser为空，由具体action判断是否需要登录
        }
      }
    }
  }

  // 加载用户权限
  async loadUserPermissions() {
    if (!this.adminUser) return;

    // 查询用户昵称补充到 adminUser
    const userInfo = await this.model('admin_user')
      .field('nickname')
      .where({ id: this.adminUser.id, is_deleted: 0 })
      .find();
    if (!think.isEmpty(userInfo)) {
      this.adminUser.nickname = userInfo.nickname || '';
    }

    const role = await this.model('admin_role')
      .where({ id: this.adminUser.role_id, is_deleted: 0 })
      .find();

    let perms = [];
    let isSuper = false;
    if (!think.isEmpty(role)) {
      isSuper = role.is_default === 1 && (role.code === 'ADMIN' || role.name === '超级管理员');
      if (!isSuper) {
        try {
          perms = JSON.parse(role.permissions || '[]');
        } catch (e) {
          perms = [];
        }
      }
    }
    this.userPermissions = perms;
    this.isSuperAdmin = isSuper;
    this.assign('userPermissions', perms);
    this.assign('isSuperAdmin', isSuper);
  }

  // 未授权处理
  handleUnauthorized() {
    if (this.isAjax()) {
      return this.fail(401, '请先登录');
    }
    return this.redirect('/admin/login.html');
  }

  // 判断是否Ajax请求
  isAjax() {
    return this.header('x-requested-with') === 'XMLHttpRequest' ||
           this.header('accept')?.includes('application/json');
  }

  // 生成JWT Token
  static generateToken(payload) {
    return jwt.sign(payload, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });
  }

  // 记录操作日志
  async log(action, module, description) {
    try {
      const user = this.adminUser || {};
      await this.model('operation_log').add({
        user_id: user.id || 0,
        username: user.username || '',
        action: action || '',
        module: module || '',
        description: description || '',
        ip: this.ctx.ip || '',
        user_agent: (this.header('user-agent') || '').slice(0, 500)
      });
    } catch (e) {
      // 日志写入失败不影响业务
    }
  }

  /**
   * 发送短信验证码
   * @param {string} mobile - 手机号
   * @param {string} bizType - 业务类型
   * @returns {Object} { success, message, code? }
   */
  async sendSmsCode(mobile, bizType) {
    const dayjs = require('dayjs');
    const smsConfig = require('../config/sms.js');
    const codeConfig = smsConfig.code;
    const ip = this.ctx.ip || '';

    // IP 发送频率限制（防止未登录接口被刷）
    const ipHourKey = `sms:ip_hour:${ip}`;
    const ipDayKey = `sms:ip_day:${ip}:${dayjs().format('YYYY-MM-DD')}`;
    const ipHourCount = (await think.cache(ipHourKey)) || 0;
    const ipDayCount = (await think.cache(ipDayKey)) || 0;
    if (ipHourCount >= 10) {
      return { success: false, message: '操作过于频繁，请稍后再试' };
    }
    if (ipDayCount >= 30) {
      return { success: false, message: '今日操作次数已达上限' };
    }

    // 检查发送频率
    const rateLimitKey = `sms:rate_limit:${mobile}:${bizType}`;
    const lastSendTime = await think.cache(rateLimitKey);
    if (lastSendTime) {
      const elapsed = Math.floor((Date.now() - lastSendTime) / 1000);
      const remaining = codeConfig.intervalSeconds - elapsed;
      if (remaining > 0) {
        return { success: false, message: `请${remaining}秒后再试` };
      }
    }

    // 检查每日发送次数
    const today = dayjs().format('YYYY-MM-DD');
    const dailyKey = `sms:daily:${mobile}:${today}`;
    const dailyCount = (await think.cache(dailyKey)) || 0;
    if (dailyCount >= codeConfig.dailyLimit) {
      return { success: false, message: '今日发送次数已达上限' };
    }

    // 生成验证码
    const code = String(Math.floor(Math.pow(10, codeConfig.length - 1) + Math.random() * 9 * Math.pow(10, codeConfig.length - 1)));
    const expireTime = dayjs().add(codeConfig.expireMinutes, 'minute').toDate();

    // 记录到数据库
    const smsLogModel = this.model('sms_log');
    const logId = await smsLogModel.add({
      mobile,
      template_id: smsConfig.templates.code,
      template_params: JSON.stringify({ code }),
      sms_type: 1,
      biz_type: bizType,
      code,
      expire_time: think.datetime(expireTime),
      status: 0,
      ip,
      create_time: think.datetime(new Date())
    });

    // 发送短信
    let sendResult = { success: true, msgId: null };
    if (smsConfig.enabled && smsConfig.smsSdkAppId && smsConfig.templates.code) {
      sendResult = await this._sendTencentSms(mobile, smsConfig.templates.code, [code, String(codeConfig.expireMinutes)]);
    } else {
      think.logger.info(`[SMS-DEV] 手机号: ${mobile}, 验证码: ${code}, 业务: ${bizType}`);
    }

    // 更新发送状态
    await smsLogModel.where({ id: logId }).update({
      status: sendResult.success ? 1 : 2,
      fail_reason: sendResult.success ? null : sendResult.message,
      provider_msg_id: sendResult.msgId
    });

    if (!sendResult.success) {
      // 腾讯云超限错误转为友好提示
      const msg = sendResult.message || '';
      if (msg.toLowerCase().includes('exceeds the upper limit')) {
        return { success: false, message: '今日发送次数已达上限' };
      }
      return { success: false, message: msg || '短信发送失败' };
    }

    // 存入缓存
    const codeKey = `sms:code:${mobile}:${bizType}`;
    await think.cache(codeKey, code, { timeout: codeConfig.expireMinutes * 60 * 1000 });
    await think.cache(rateLimitKey, Date.now(), { timeout: codeConfig.intervalSeconds * 1000 });
    await think.cache(dailyKey, dailyCount + 1, { timeout: 24 * 60 * 60 * 1000 });
    // 更新 IP 计数器
    await think.cache(ipHourKey, ipHourCount + 1, { timeout: 60 * 60 * 1000 });
    await think.cache(ipDayKey, ipDayCount + 1, { timeout: 24 * 60 * 60 * 1000 });

    return { success: true, message: '验证码已发送', code };
  }

  /**
   * 校验短信验证码
   */
  async verifySmsCode(mobile, bizType, code) {
    const codeKey = `sms:code:${mobile}:${bizType}`;
    const cachedCode = await think.cache(codeKey);

    if (!cachedCode) {
      return { success: false, message: '验证码已过期，请重新获取' };
    }
    if (cachedCode !== code) {
      return { success: false, message: '验证码错误' };
    }

    await think.cache(codeKey, null);
    return { success: true, message: '验证成功' };
  }

  /**
   * 发送通知短信（非验证码类）
   * @param {string} mobile - 手机号
   * @param {string} templateId - 模板ID
   * @param {string[]} templateParams - 模板参数数组
   * @param {string} bizType - 业务类型（用于日志）
   * @returns {Object} { success, message }
   */
  async sendNotifySms(mobile, templateId, templateParams = [], bizType = 'notify') {
    const smsConfig = require('../config/sms.js');
    const ip = this.ctx?.ip || '';

    think.logger.info(`[SMS] sendNotifySms 开始 - 手机号: ${mobile}, 模板: ${templateId}, 参数: ${JSON.stringify(templateParams)}, 业务: ${bizType}`);
    think.logger.info(`[SMS] 配置状态 - enabled: ${smsConfig.enabled}, smsSdkAppId: ${smsConfig.smsSdkAppId || '(空)'}, signName: ${smsConfig.signName || '(空)'}`);

    // 记录到数据库
    const smsLogModel = this.model('sms_log');
    const logId = await smsLogModel.add({
      mobile,
      template_id: templateId,
      template_params: JSON.stringify(templateParams),
      sms_type: 2,
      biz_type: bizType,
      code: '',
      status: 0,
      ip,
      create_time: think.datetime(new Date())
    });
    think.logger.info(`[SMS] 日志已写入数据库 logId: ${logId}`);

    let sendResult = { success: true, msgId: null };
    if (smsConfig.enabled && smsConfig.smsSdkAppId) {
      think.logger.info(`[SMS] 调用腾讯云短信接口...`);
      sendResult = await this._sendTencentSms(mobile, templateId, templateParams);
    } else {
      think.logger.info(`[SMS-DEV] 未启用真实发送 - enabled: ${smsConfig.enabled}, smsSdkAppId: ${smsConfig.smsSdkAppId || '(空)'}`);
      think.logger.info(`[SMS-DEV] 通知短信 手机号: ${mobile}, 模板: ${templateId}, 参数: ${JSON.stringify(templateParams)}, 业务: ${bizType}`);
    }

    think.logger.info(`[SMS] sendNotifySms 结果 - success: ${sendResult.success}, msgId: ${sendResult.msgId || '(无)'}, message: ${sendResult.message || '(无)'}`);

    await smsLogModel.where({ id: logId }).update({
      status: sendResult.success ? 1 : 2,
      fail_reason: sendResult.success ? null : sendResult.message,
      provider_msg_id: sendResult.msgId
    });

    return sendResult;
  }

  /**
   * 发送腾讯云短信
   * @private
   */
  async _sendTencentSms(mobile, templateId, templateParams) {
    const smsConfig = require('../config/sms.js');
    try {
      const tencentcloud = require('tencentcloud-sdk-nodejs');
      const SmsClient = tencentcloud.sms.v20210111.Client;

      const client = new SmsClient({
        credential: {
          secretId: smsConfig.secretId,
          secretKey: smsConfig.secretKey
        },
        region: smsConfig.region,
        profile: {
          httpProfile: { endpoint: 'sms.tencentcloudapi.com' }
        }
      });

      const reqParams = {
        PhoneNumberSet: [`+86${mobile}`],
        SmsSdkAppId: smsConfig.smsSdkAppId,
        SignName: smsConfig.signName,
        TemplateId: templateId,
        TemplateParamSet: templateParams
      };
      think.logger.info(`[SMS] _sendTencentSms 请求参数: ${JSON.stringify(reqParams)}`);

      const result = await client.SendSms(reqParams);
      think.logger.info(`[SMS] _sendTencentSms 响应: ${JSON.stringify(result)}`);

      const sendStatus = result.SendStatusSet?.[0];
      if (sendStatus?.Code === 'Ok') {
        think.logger.info(`[SMS] 发送成功 SerialNo: ${sendStatus.SerialNo}`);
        return { success: true, msgId: sendStatus.SerialNo };
      }
      think.logger.error(`[SMS] 发送失败 Code: ${sendStatus?.Code}, Message: ${sendStatus?.Message}`);
      return { success: false, message: sendStatus?.Message || '发送失败' };
    } catch (error) {
      think.logger.error('[SMS] 腾讯云短信发送异常:', error.message);
      think.logger.error('[SMS] 异常堆栈:', error.stack);
      return { success: false, message: error.message };
    }
  }

  static get JWT_SECRET() {
    return JWT_SECRET;
  }

  static get JWT_EXPIRES_IN() {
    return JWT_EXPIRES_IN;
  }
};
