/**
 * 登录认证工具类
 * 实现30天免登录功能（实际由后端Token有效期控制，当前为7天）
 * 
 * 功能：
 * - 本地登录状态检查
 * - 服务端Token验证
 * - 微信手机号快速登录
 * - 登录状态持久化
 */

const config = require('../config/index')
const api = require('./api')

// 存储键名
const TOKEN_KEY = config.STORAGE_KEYS.TOKEN
const USER_KEY = config.STORAGE_KEYS.USER_INFO
const USER_ID_KEY = config.STORAGE_KEYS.USER_ID
const TOKEN_EXPIRY_KEY = config.STORAGE_KEYS.TOKEN_EXPIRY

/**
 * 检查是否已登录（本地验证）
 * 仅检查本地存储，不发起网络请求
 * @returns {boolean} 是否已登录
 */
function isLoggedIn() {
  const token = wx.getStorageSync(TOKEN_KEY)
  const expiry = wx.getStorageSync(TOKEN_EXPIRY_KEY)

  if (!token) return false

  // 如果有过期时间，检查是否过期
  if (expiry) {
    return new Date(expiry) > new Date()
  }

  // 没有过期时间但有token，认为已登录（兼容旧数据）
  return true
}

/**
 * 获取本地保存的用户信息
 * @returns {object|null} 用户信息
 */
function getLocalUserInfo() {
  return wx.getStorageSync(USER_KEY) || null
}

/**
 * 获取登录Token
 * @returns {string|null} Token
 */
function getToken() {
  return wx.getStorageSync(TOKEN_KEY) || null
}

/**
 * 获取用户ID
 * @returns {string|null} 用户ID
 */
function getUserId() {
  return wx.getStorageSync(USER_ID_KEY) || null
}

/**
 * 验证登录状态（服务端验证）
 * 调用后端API验证Token是否有效
 * @returns {Promise<{valid: boolean, user?: object, expired?: boolean, error?: any}>}
 */
async function verifyLogin() {
  const token = getToken()
  if (!token) {
    return { valid: false }
  }

  try {
    const res = await api.auth.getCurrentUser()

    if (res.success && res.data) {
      // 更新本地用户信息
      saveUserInfo(res.data, token)
      return { valid: true, user: res.data }
    } else {
      // Token无效，清除本地数据
      clearLoginInfo()
      return { valid: false, expired: true }
    }
  } catch (error) {
    console.error('验证登录失败:', error)

    // 401错误表示Token过期
    if (error.code === 401) {
      clearLoginInfo()
      return { valid: false, expired: true }
    }

    // 网络错误等情况，保持本地状态
    return { valid: false, error }
  }
}

/**
 * 微信手机号快速登录
 * @param {string} code - 微信getPhoneNumber返回的code
 * @returns {Promise<{success: boolean, user?: object, error?: string}>}
 */
async function wxPhoneLogin(code, loginCode) {
  try {
    const res = await api.auth.wxPhoneLogin(code, loginCode)

    if (res.success && res.data) {
      const { token, user } = res.data

      // 计算过期时间（7天后，与后端保持一致）
      const expiresAt = new Date()
      expiresAt.setDate(expiresAt.getDate() + 7)

      // 保存登录信息
      saveUserInfo(user, token, expiresAt.toISOString())

      return { success: true, user }
    }

    return { success: false, error: res.error || '登录失败' }
  } catch (error) {
    console.error('微信手机号登录失败:', error)
    return { success: false, error: error.message || '网络错误' }
  }
}

/**
 * 保存用户信息到本地
 * @param {object} user - 用户信息
 * @param {string} token - 登录Token
 * @param {string} expiresAt - 过期时间（可选）
 */
function saveUserInfo(user, token, expiresAt = null) {
  if (token) {
    wx.setStorageSync(TOKEN_KEY, token)
  }

  if (user) {
    wx.setStorageSync(USER_KEY, user)
    if (user.id) {
      wx.setStorageSync(USER_ID_KEY, user.id)
    }
  }

  if (expiresAt) {
    wx.setStorageSync(TOKEN_EXPIRY_KEY, expiresAt)
  }

  // 登录成功后，检查并绑定推荐码
  if (user && user.id && token) {
    checkAndBindReferralCode(user.id, token)
  }
}

/**
 * 检查并绑定推荐码（佣金系统）
 * 在用户登录成功后自动调用
 * 包含重试机制，确保网络波动时也能成功绑定
 * @param {string} userId - 用户ID
 * @param {string} token - 登录token
 * @param {number} retryCount - 重试次数（内部使用）
 */
async function checkAndBindReferralCode(userId, token, retryCount = 0) {
  const MAX_RETRY = 3
  const REFERRAL_CODE_KEY = 'pendingReferralCode'

  try {
    const referralCode = wx.getStorageSync(REFERRAL_CODE_KEY)

    if (!referralCode) {
      console.log('[推荐码绑定] 没有待绑定的推荐码')
      return
    }

    console.log(`[推荐码绑定] 检测到待绑定推荐码: ${referralCode}, 重试次数: ${retryCount}`)

    const res = await api.commission.bindReferral(referralCode)

    if (res.success) {
      wx.removeStorageSync(REFERRAL_CODE_KEY)
      const app = getApp()
      if (app && app.globalData) {
        app.globalData.pendingReferralCode = null
      }
      console.log('[推荐码绑定] 推荐关系绑定成功')
    } else {
      console.log('[推荐码绑定] 推荐关系绑定失败:', res.error)

      if (res.error && (
        res.error.includes('已绑定') ||
        res.error.includes('自己') ||
        res.error.includes('无效')
      )) {
        wx.removeStorageSync(REFERRAL_CODE_KEY)
        const app = getApp()
        if (app && app.globalData) {
          app.globalData.pendingReferralCode = null
        }
        console.log('[推荐码绑定] 已清除无效的推荐码')
      } else if (retryCount < MAX_RETRY) {
        console.log(`[推荐码绑定] 将在5秒后进行第${retryCount + 1}次重试...`)
        await new Promise(resolve => setTimeout(resolve, 5000))
        await checkAndBindReferralCode(userId, token, retryCount + 1)
      } else {
        console.log('[推荐码绑定] 重试次数已用尽，绑定失败')
      }
    }
  } catch (error) {
    console.error('[推荐码绑定] 绑定推荐码失败:', error)

    if (retryCount < MAX_RETRY) {
      console.log(`[推荐码绑定] 网络错误，5秒后进行第${retryCount + 1}次重试...`)
      await new Promise(resolve => setTimeout(resolve, 5000))
      await checkAndBindReferralCode(userId, token, retryCount + 1)
    } else {
      console.log('[推荐码绑定] 重试次数已用尽，网络错误')
    }
  }
}

/**
 * 清除登录信息
 */
function clearLoginInfo() {
  wx.removeStorageSync(TOKEN_KEY)
  wx.removeStorageSync(USER_KEY)
  wx.removeStorageSync(USER_ID_KEY)
  wx.removeStorageSync(TOKEN_EXPIRY_KEY)
  wx.removeStorageSync(config.STORAGE_KEYS.REFRESH_TOKEN)
}

/**
 * 退出登录
 * @returns {Promise<void>}
 */
async function logout() {
  const token = getToken()

  if (token) {
    try {
      await api.auth.logout()
    } catch (error) {
      console.error('退出登录API调用失败:', error)
    }
  }

  clearLoginInfo()
}

/**
 * 检查并恢复登录状态
 * 用于小程序启动时调用
 * @returns {Promise<{isLoggedIn: boolean, user?: object}>}
 */
async function checkAndRestoreLogin() {
  // 1. 先检查本地状态
  if (!isLoggedIn()) {
    return { isLoggedIn: false }
  }

  // 2. 验证服务端状态
  const result = await verifyLogin()

  if (result.valid) {
    return { isLoggedIn: true, user: result.user }
  }

  // 3. 验证失败，清除本地状态
  if (result.expired) {
    console.log('Token已过期，需要重新登录')
  }

  return { isLoggedIn: false }
}

/**
 * 需要登录时的处理
 * 跳转到登录页面
 * @param {string} redirectUrl - 登录成功后跳转的URL（可选）
 */
function requireLogin(redirectUrl = '') {
  const url = redirectUrl
    ? `/pages/login/login?redirect=${encodeURIComponent(redirectUrl)}`
    : '/pages/login/login'

  wx.navigateTo({
    url,
    fail: () => {
      // 如果navigateTo失败，尝试redirectTo
      wx.redirectTo({ url })
    }
  })
}

/**
 * 显示登录提示弹窗
 * @param {string} redirectUrl - 登录成功后跳转的URL（可选）
 * @returns {Promise<boolean>} 用户是否选择去登录
 */
function showLoginTip(redirectUrl = '') {
  return new Promise((resolve) => {
    wx.showModal({
      title: '提示',
      content: '请先登录后再操作',
      confirmText: '去登录',
      confirmColor: '#b06ab3',
      success: (res) => {
        if (res.confirm) {
          requireLogin(redirectUrl)
          resolve(true)
        } else {
          resolve(false)
        }
      }
    })
  })
}

/**
 * 页面级登录验证（统一验证机制）
 * 用于页面onLoad时调用，确保用户已登录且token有效
 * 
 * @param {object} options - 配置选项
 * @param {string} options.pageName - 页面名称（用于日志）
 * @param {string} options.redirectUrl - 未登录时的跳转URL
 * @param {boolean} options.silent - 是否静默失败（不显示提示）
 * @returns {Promise<boolean>} 是否已登录且token有效
 * 
 * @example
 * // 在页面onLoad中使用
 * async onLoad() {
 *   const isValid = await auth.ensureLogin({
 *     pageName: 'gift-shop',
 *     redirectUrl: '/pages/gift-shop/gift-shop'
 *   })
 *   
 *   if (!isValid) return
 *   
 *   // 继续加载页面数据
 *   this.loadData()
 * }
 */
async function ensureLogin(options = {}) {
  const {
    pageName = 'unknown',
    redirectUrl = '',
    silent = false
  } = options

  const config = require('../config/index')
  const app = getApp()

  console.log(`[auth.ensureLogin] ${pageName} - 开始验证登录状态`)

  // 1. 等待app初始化完成
  if (app && app.waitForLoginCheck) {
    await app.waitForLoginCheck()
    console.log(`[auth.ensureLogin] ${pageName} - app登录检查完成`)
  }

  // 2. 检查全局登录状态
  if (!app || !app.globalData || !app.globalData.isLoggedIn) {
    console.warn(`[auth.ensureLogin] ${pageName} - 全局状态显示未登录`)
    if (!silent) {
      wx.redirectTo({
        url: `/pages/login/login?redirect=${encodeURIComponent(redirectUrl)}`
      })
    }
    return false
  }

  // 3. 检查token是否存在（最多重试3次）
  let token = null
  let retryCount = 0
  const maxRetries = 3

  while (!token && retryCount < maxRetries) {
    token = wx.getStorageSync(config.STORAGE_KEYS.TOKEN)

    if (!token) {
      retryCount++
      console.warn(`[auth.ensureLogin] ${pageName} - Token不存在，第${retryCount}次重试`)

      if (retryCount < maxRetries) {
        // 等待递增的时间：100ms, 200ms, 300ms
        await new Promise(resolve => setTimeout(resolve, retryCount * 100))
      }
    }
  }

  if (!token) {
    console.error(`[auth.ensureLogin] ${pageName} - Token在${maxRetries}次重试后仍然不存在`)
    if (!silent) {
      wx.redirectTo({
        url: `/pages/login/login?redirect=${encodeURIComponent(redirectUrl)}`
      })
    }
    return false
  }

  // 4. 检查token是否过期
  const expiry = wx.getStorageSync(config.STORAGE_KEYS.TOKEN_EXPIRY)
  if (expiry && new Date(expiry) <= new Date()) {
    console.warn(`[auth.ensureLogin] ${pageName} - Token已过期`)
    clearLoginInfo()
    if (app && app.globalData) {
      app.globalData.isLoggedIn = false
    }
    if (!silent) {
      wx.redirectTo({
        url: `/pages/login/login?redirect=${encodeURIComponent(redirectUrl)}`
      })
    }
    return false
  }

  // 5. 最终验证：再次确认token可以被获取（防止storage异步问题）
  await new Promise(resolve => setTimeout(resolve, 50))
  const finalToken = wx.getStorageSync(config.STORAGE_KEYS.TOKEN)
  if (!finalToken) {
    console.error(`[auth.ensureLogin] ${pageName} - 最终验证失败，token无法获取`)
    if (!silent) {
      wx.redirectTo({
        url: `/pages/login/login?redirect=${encodeURIComponent(redirectUrl)}`
      })
    }
    return false
  }

  console.log(`[auth.ensureLogin] ${pageName} - 验证通过，token有效 (长度: ${finalToken.length})`)
  return true
}

module.exports = {
  // 状态检查
  isLoggedIn,
  getLocalUserInfo,
  getToken,
  getUserId,

  // 登录验证
  verifyLogin,
  checkAndRestoreLogin,
  ensureLogin,  // 新增：统一的页面级登录验证

  // 登录操作
  wxPhoneLogin,
  logout,

  // 数据管理
  saveUserInfo,
  clearLoginInfo,

  // 推荐码绑定
  checkAndBindReferralCode,

  // 辅助方法
  requireLogin,
  showLoginTip
}
