const Framework = require("../../framework/node-core-framework.js");

module.exports = {
  /**
   * @swagger
   * /api/user/login:
   *   post:
   *     summary: 用户登录
   *     description: 通过邮箱和密码登录，返回token、device_id和用户信息
   *     tags: [前端-用户管理]
   *     requestBody:
   *       required: true
   *       content:
   *         application/json:
   *           schema:
   *             type: object
   *             required:
   *               - email
   *               - password
   *             properties:
   *               email:
   *                 type: string
   *                 description: 邮箱（登录名）
   *                 example: 'user@example.com'
   *               password:
   *                 type: string
   *                 description: 密码
   *                 example: 'password123'
   *               device_id:
   *                 type: string
   *                 description: 设备ID（客户端生成，可选，如果提供则使用提供的，否则使用数据库中的）
   *                 example: 'device_1234567890abcdef'
   *     responses:
   *       200:
   *         description: 登录成功
   *         content:
   *           application/json:
   *             schema:
   *               type: object
   *               properties:
   *                 code:
   *                   type: integer
   *                   description: 状态码，0表示成功
   *                   example: 0
   *                 message:
   *                   type: string
   *                   description: 响应消息
   *                   example: 'success'
   *                 data:
   *                   type: object
   *                   properties:
   *                     token:
   *                       type: string
   *                       description: 认证token
   *                       example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
   *                     device_id:
   *                       type: string
   *                       description: 设备ID
   *                       example: 'device_123456'
   *                     user:
   *                       type: object
   *                       description: 用户信息
   *       400:
   *         description: 参数错误或用户不存在
   *         content:
   *           application/json:
   *             schema:
   *               type: object
   *               properties:
   *                 code:
   *                   type: integer
   *                   example: 400
   *                 message:
   *                   type: string
   *                   example: '用户不存在或密码错误'
   */
  "POST /user/login": async (ctx) => {
    const { login_name:email, password, device_id: client_device_id } = ctx.getBody();
    const dayjs = require('dayjs');
    const { verifyPassword, validateDeviceId, maskEmail } = require('../utils/crypto_utils');

    // 参数验证
    if (!email || !password) {
      return ctx.fail('邮箱和密码不能为空');
    }

    // 统一邮箱地址为小写
    const email_normalized = email.toLowerCase().trim();

    // 验证邮箱格式
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(email_normalized)) {
      return ctx.fail('邮箱格式不正确');
    }

    // 验证密码长度
    if (password.length < 6 || password.length > 50) {
      return ctx.fail('密码长度不正确');
    }

    const { pla_account } = await Framework.getModels();

    try {
      // 根据邮箱查找用户（使用统一的小写邮箱）
      const user = await pla_account.findOne({
        where: {
          login_name: email_normalized
        }
      });

      if (!user) {
        // 防止用户枚举攻击：统一返回相同的错误信息
        return ctx.fail('邮箱或密码错误');
      }

      // 验证密码（支持新旧格式）
      let isPasswordValid = false;

      if (user.pwd && user.pwd.includes('$')) {
        // 新格式：加密密码
        isPasswordValid = await verifyPassword(password, user.pwd);
      } else {
        // 旧格式：明文密码（临时兼容，建议尽快迁移）
        isPasswordValid = (user.pwd === password);

        // 如果验证通过，自动升级为加密密码
        if (isPasswordValid) {
          const { hashPassword } = require('../utils/crypto_utils');
          const hashedPassword = await hashPassword(password);
          await pla_account.update(
            { pwd: hashedPassword },
            { where: { id: user.id } }
          );
          console.log(`[安全升级] 用户 ${maskEmail(email_normalized)} 的密码已自动加密`);
        }
      }

      if (!isPasswordValid) {
        // 记录失败尝试（用于后续添加防暴力破解功能）
        console.warn(`[登录失败] 邮箱: ${maskEmail(email_normalized)}, 时间: ${new Date().toISOString()}`);
        return ctx.fail('邮箱或密码错误');
      }

      // 检查账号是否启用
      if (!user.is_enabled) {
        return ctx.fail('账号已被禁用，请联系管理员');
      }

      // 检查授权状态（仅记录，不拒绝登录）
      const userData = user.toJSON();
      const authDate = userData.authorization_date;
      const authDays = userData.authorization_days || 0;

      // 使用工具函数计算剩余天数
      const { calculateRemainingDays } = require('../utils/account_utils');
      const remaining_days = calculateRemainingDays(authDate, authDays);

      // 处理设备ID
      let device_id = client_device_id;

      // 验证客户端提供的 device_id 格式
      if (client_device_id) {
        // if (!validateDeviceId(client_device_id)) {
        //   return ctx.fail('设备ID格式不正确，请重新登录');
        // }

        // 如果与数据库不同，需要额外验证（防止设备ID劫持）
        if (user.device_id && client_device_id !== user.device_id) {
          // 记录设备更换
          console.warn(`[设备更换] 用户 ${maskEmail(email_normalized)} 更换设备: ${user.device_id} -> ${client_device_id}`);

          // TODO: 这里可以添加更多安全检查，如：
          // - 发送验证码确认
          // - 记录到安全日志
          // - 限制更换频率
        }

        // 更新设备ID
        if (client_device_id !== user.device_id) {
          await pla_account.update(
            { device_id: client_device_id },
            { where: { id: user.id } }
          );
        }
      } else {
        // 使用数据库中的设备ID
        device_id = user.device_id;
      }

      // 如果仍然没有设备ID，返回错误
      if (!device_id) {
        return ctx.fail('设备ID不能为空，请重新登录');
      }

      // 创建token
      const token = Framework.getServices().tokenService.create({
        sn_code: user.sn_code,
        device_id: device_id,
        id: user.id
      });

      // 构建安全的用户信息响应（白名单模式）
      const safeUserInfo = {
        id: user.id,
        sn_code: user.sn_code,
        login_name: maskEmail(user.login_name), // 脱敏处理
        is_enabled: user.is_enabled,
        authorization_date: user.authorization_date,
        authorization_days: user.authorization_days,
        remaining_days: remaining_days,
        auto_deliver: user.auto_deliver,
        deliver_config: user.deliver_config,
        created_at: user.created_at,
        updated_at: user.updated_at
      };

      // 记录成功登录
      console.log(`[登录成功] 用户 ${maskEmail(email_normalized)}, 剩余天数: ${remaining_days}`);

      return ctx.success({
        token,
        device_id,
        user: safeUserInfo
      });
    } catch (error) {
      // 记录详细错误但不暴露给客户端
      console.error('[登录异常]', {
        error: error.message,
        stack: error.stack,
        email: maskEmail(email_normalized)
      });
      return ctx.fail('登录失败，请稍后重试');
    }
  },

  /**
   * @swagger
   * /api/user/delivery-config/get:
   *   post:
   *     summary: 获取投递配置
   *     description: 根据设备SN码获取用户的投递配置，返回 pla_account 表中的 deliver_config 对象
   *     tags: [前端-用户管理]
   *     requestBody:
   *       required: true
   *       content:
   *         application/json:
   *           schema:
   *             type: object
   *             required:
   *               - sn_code
   *             properties:
   *               sn_code:
   *                 type: string
   *                 description: 设备SN码
   *     responses:
   *       200:
   *         description: 获取成功
   *         content:
   *           application/json:
   *             schema:
   *               type: object
   *               properties:
   *                 code:
   *                   type: integer
   *                   example: 0
   *                 message:
   *                   type: string
   *                   example: 'success'
   *                 data:
   *                   type: object
   *                   properties:
   *                     deliver_config:
   *                       type: object
   *                       description: 自动投递配置对象，如果不存在则返回 null
   *                       nullable: true
   */
  'POST /user/delivery-config/get': async (ctx) => {
    try {
      const body = ctx.getBody();
      const { sn_code } = body;

      if (!sn_code) {
        return ctx.fail('请提供设备SN码');
      }

      const { pla_account } = await Framework.getModels();

      // 根据 sn_code 查找账号
      const user = await pla_account.findOne({
        where: { sn_code }
      });

      if (!user) {
        return ctx.fail('用户不存在');
      }

      // 从 pla_account 表的 deliver_config 字段获取配置
      const deliver_config = user.deliver_config || null;

      return ctx.success({ deliver_config });
    } catch (error) {
      console.error('[获取投递配置失败]', {
        error: error.message,
        timestamp: new Date().toISOString()
      });
      return ctx.fail('获取投递配置失败');
    }
  },

  /**
   * @swagger
   * /api/user/delivery-config/save:
   *   post:
   *     summary: 保存投递配置
   *     description: 根据设备SN码保存用户的投递配置到 pla_account 表的 deliver_config 字段
   *     tags: [前端-用户管理]
   *     requestBody:
   *       required: true
   *       content:
   *         application/json:
   *           schema:
   *             type: object
   *             required:
   *               - sn_code
   *               - deliver_config
   *             properties:
   *               sn_code:
   *                 type: string
   *                 description: 设备SN码
   *               deliver_config:
   *                 type: object
   *                 description: 自动投递配置对象
   *                 properties:
   *                   auto_delivery:
   *                     type: boolean
   *                     description: 是否启用自动投递
   *                   interval:
   *                     type: integer
   *                     description: 投递间隔（分钟）
   *                   min_salary:
   *                     type: integer
   *                     description: 最低薪资
   *                   max_salary:
   *                     type: integer
   *                     description: 最高薪资
   *                   scroll_pages:
   *                     type: integer
   *                     description: 滚动页数
   *                   max_per_batch:
   *                     type: integer
   *                     description: 每批最多投递数
   *                   filter_keywords:
   *                     type: string
   *                     description: 过滤关键词
   *                   exclude_keywords:
   *                     type: string
   *                     description: 排除关键词
   *                   start_time:
   *                     type: string
   *                     description: 开始时间（格式：HH:mm）
   *                   end_time:
   *                     type: string
   *                     description: 结束时间（格式：HH:mm）
   *                   workdays_only:
   *                     type: boolean
   *                     description: 仅工作日
   *     responses:
   *       200:
   *         description: 保存成功
   */
  'POST /user/delivery-config/save': async (ctx) => {
    try {
      const body = ctx.getBody();
      const { sn_code, deliver_config } = body;

      if (!sn_code) {
        return ctx.fail('请提供设备SN码');
      }

      if (!deliver_config) {
        return ctx.fail('请提供 deliver_config 配置对象');
      }

      // 验证 deliver_config 的基本结构
      if (typeof deliver_config !== 'object') {
        return ctx.fail('deliver_config 必须是对象');
      }

      const { pla_account } = await Framework.getModels();

      // 根据 sn_code 查找账号
      const user = await pla_account.findOne({
        where: { sn_code }
      });

      if (!user) {
        return ctx.fail('用户不存在');
      }

      // 更新 pla_account 表的 deliver_config 和 auto_deliver 字段
      await pla_account.update(
        {
          deliver_config: deliver_config,
          auto_deliver: deliver_config.auto_delivery ? 1 : 0
        },
        { where: { id: user.id } }
      );

      console.log('[保存投递配置成功]', {
        sn_code,
        auto_delivery: deliver_config.auto_delivery,
        timestamp: new Date().toISOString()
      });

      return ctx.success({ message: '配置保存成功' });
    } catch (error) {
      console.error('[保存投递配置失败]', {
        error: error.message,
        timestamp: new Date().toISOString()
      });
      return ctx.fail('保存投递配置失败');
    }
  }
}