import { createStore } from 'vuex'
import type { Router } from 'vue-router'
import { fetchUserRoutes } from '@/api/menu'
import type { MenuItemRaw } from '@/api/menu'
import { buildDynamicRoutes } from '@/router/dynamicRoutes'
import { fetchIndustryTree, fetchJobCategoryTree, fetchRegionTree } from '@/api/common'
import type { IndustryItem, JobCategoryItem, RegionItem } from '@/api/common'
import { fetchJobIntention, saveJobIntention } from '@/api/jobs'
import type { JobIntention } from '@/api/jobs'
import { fetchUserInfo } from '@/api/auth'
import type { UserInfo } from '@/api/auth'
import { fetchMemberStatus } from '@/api/member'
import type { MemberStatus } from '@/api/member'
import { createChannelBridge } from '@/utils/channelBridge'
import { PLUGIN_TARGET_VERSION } from '@/business.config'

/** 招聘分类选项：label → 接口参数 recruitCategory */
export const JOB_TYPE_OPTIONS: { label: string; value: number }[] = [
  { label: '全部', value: null },
  { label: '社招', value: 0 },
  { label: '校招', value: 1 },
  { label: '实习', value: 2 },
]

/** 招聘分类映射：数字 → 中文标签 */
export const JOB_TYPE_MAP: Record<number, string> = Object.fromEntries(
  JOB_TYPE_OPTIONS.map(item => [item.value, item.label]),
)

/** 根据 recruitCategory 值获取中文标签，未匹配返回空字符串 */
export function formatEmploymentType(type: number | undefined | null): string {
  if (type === undefined || type === null) return ''
  return JOB_TYPE_MAP[type] ?? ''
}

/** 学历要求映射：数字 → 中文标签（0=不限 1=大专 2=本科 3=硕士 4=博士） */
export const EDUCATION_MAP: Record<number, string> = {
  0: '不限',
  1: '大专',
  2: '本科',
  3: '硕士',
  4: '博士',
}

/** 根据 education 值获取中文标签，未匹配返回空字符串 */
export function formatEducation(edu: number | undefined | null): string {
  if (edu === undefined || edu === null) return ''
  return EDUCATION_MAP[edu] ?? ''
}

/** 职位列表页缓存数据（从详情页返回时恢复用） */
export interface JobListCache {
  /** 缓存时所在的 Tab（recommend / collected / applied） */
  tab: string
  /** 缓存的职位列表 */
  list: any[]
  /** 当前已加载到的页码 */
  pageNum: number
  /** 总记录数 */
  total: number
  /** 列表滚动位置 */
  scrollTop: number
}

/** 导师列表页缓存数据（从详情页返回时恢复用） */
export interface MentorListCache {
  /** 缓存的导师列表 */
  list: any[]
  /** 当前已加载到的页码 */
  pageNum: number
  /** 列表滚动位置 */
  scrollTop: number
}

export interface RootState {
  appName: string
  showLogin: boolean
  loginRedirect: string

  /**
   * 登录状态 — 登录成功设为 true，退出成功设为 false
   * 因为后端 Cookie 是 HttpOnly 的，前端 JS 无法读取，所以用内存状态管理
   */
  isAuthenticated: boolean

  /**
   * 后端返回的原始菜单数据，SideNav 用它来渲染导航
   */
  dynamicMenus: MenuItemRaw[]

  /**
   * 标记动态路由是否已经加载过，避免重复请求
   * 每次登出时重置为 false
   */
  routesLoaded: boolean

  /**
   * 记录已注册的动态路由 name，登出时用来逐个 removeRoute
   */
  dynamicRouteNames: string[]

  /**
   * 行业树分类数据（一级二级嵌套）
   * 由 /public/industries/tree 接口返回，进首页和 Jobs 页时刷新
   * 其他页面/组件可直接从 store 读取
   */
  industries: IndustryItem[]

  /**
   * 岗位树分类数据（一级二级三级嵌套）
   * 由 /public/job-categories/tree 接口返回，进首页和 Jobs 页时刷新
   * 其他页面/组件可直接从 store 读取
   */
  jobCategories: JobCategoryItem[]

  /**
   * 地区树分类数据（省市区三级嵌套）
   * 由 /public/regions/tree 接口返回，进首页和 Jobs 页时刷新
   * 其他页面/组件可直接从 store 读取
   */
  regions: RegionItem[]

  /**
   * 职位列表页缓存 — 从详情页返回时恢复列表和滚动位置
   * 为 null 表示没有缓存，需要重新请求
   */
  jobListCache: JobListCache | null

  /**
   * 导师列表页缓存 — 从详情页返回时恢复列表和滚动位置
   * 为 null 表示没有缓存，需要重新请求
   */
  mentorListCache: MentorListCache | null

  /**
   * 求职意向数据 — JobGoalDialog 和 Jobs 页面共享
   * 由 loadJobIntention action 从接口加载，saveJobIntention action 保存后更新
   */
  jobIntention: JobIntention

  /**
   * 用户个人信息 — 登录后从 /user/manage/info 接口获取
   * 多个页面可直接从 store 读取
   */
  userInfo: UserInfo | null

  /**
   * 会员状态信息 — 登录后从 /member/status 接口获取
   * 多个页面可直接从 store 读取
   */
  memberStatus: MemberStatus | null

  /**
   * 设置弹窗 — 控制显示/隐藏及初始 Tab
   */
  showSettings: boolean
  settingsTab: string

  /**
   * 邀请码 — 从 URL 参数 invite_code 中提取
   * 登录成功后自动清空，避免重复发送
   */
  inviteCode: string

  /**
   * 全局会员权限拦截弹窗 — 路由守卫或页面检测到免费用户时触发
   */
  showMemberAccessDialog: boolean

  /** 通信桥接组件的域名标识（用于 BroadcastChannel 频道隔离） */
  bridgeDomain: string

  /** 浏览器插件是否在线（3秒内有 BroadcastChannel 心跳则为 true） */
  plugIsOnline: boolean

  /** 插件当前使用版本（从通信数据 offerpieBrowserPlugUsage.version 获取） */
  plugUseVersion: string

  /** 插件目标版本（手动设置，用于判断是否需要更新） */
  plugTargetVersion: string

  /** 插件是否是最新版本（plugUseVersion === plugTargetVersion） */
  isLatestPlugin: boolean
}

export default createStore<RootState>({
  state: {
    appName: 'JobAssistant',
    showLogin: false,
    loginRedirect: '',
    isAuthenticated: sessionStorage.getItem('isAuthenticated') === 'true',
    dynamicMenus: [],
    routesLoaded: false,
    dynamicRouteNames: [],
    industries: [],
    jobCategories: [],
    regions: [],
    jobListCache: null,
    mentorListCache: null,
    jobIntention: {
      categoryIds: [],
      regionCodes: [],
      industryIds: [],
      employmentType: null,
      recruitCategory: null,
      aiCategoryIds: [],
      aiIndustryIds: [],
    },
    userInfo: null,
    memberStatus: null,
    showSettings: false,
    settingsTab: 'account',
    inviteCode: '',
    showMemberAccessDialog: false,
    /** 通信桥接组件的域名标识（用于 BroadcastChannel 频道隔离） */
    bridgeDomain: 'offerpai.com.cn',
    /** 浏览器插件是否在线 */
    plugIsOnline: false,
    /** 插件当前使用版本 */
    plugUseVersion: '',
    /** 插件目标版本 */
    plugTargetVersion: PLUGIN_TARGET_VERSION,
    /** 插件是否是最新版本 */
    isLatestPlugin: true,
  },
  getters: {
    getAppName: (state) => state.appName,
  },
  mutations: {
    SET_APP_NAME(state, name: string) {
      state.appName = name
    },
    SET_SHOW_LOGIN(state, show: boolean) {
      state.showLogin = show
    },
    SET_LOGIN_REDIRECT(state, path: string) {
      state.loginRedirect = path
    },
    SET_AUTHENTICATED(state, val: boolean) {
      state.isAuthenticated = val
      if (val) {
        sessionStorage.setItem('isAuthenticated', 'true')
      } else {
        sessionStorage.removeItem('isAuthenticated')
      }
    },
    SET_DYNAMIC_MENUS(state, menus: MenuItemRaw[]) {
      state.dynamicMenus = menus
    },
    SET_ROUTES_LOADED(state, loaded: boolean) {
      state.routesLoaded = loaded
    },
    SET_DYNAMIC_ROUTE_NAMES(state, names: string[]) {
      state.dynamicRouteNames = names
    },
    SET_INDUSTRIES(state, data: IndustryItem[]) {
      state.industries = data
    },
    SET_JOB_CATEGORIES(state, data: JobCategoryItem[]) {
      state.jobCategories = data
    },
    SET_REGIONS(state, data: RegionItem[]) {
      state.regions = data
    },
    SET_JOB_LIST_CACHE(state, cache: JobListCache | null) {
      state.jobListCache = cache
    },
    SET_MENTOR_LIST_CACHE(state, cache: MentorListCache | null) {
      state.mentorListCache = cache
    },
    SET_JOB_INTENTION(state, data: JobIntention) {
      state.jobIntention = {
        categoryIds: data.categoryIds ?? [],
        regionCodes: data.regionCodes ?? [],
        industryIds: data.industryIds ?? [],
        employmentType: data.employmentType ?? null,
        recruitCategory: data.recruitCategory ?? null,
        aiCategoryIds: data.aiCategoryIds ?? [],
        aiIndustryIds: data.aiIndustryIds ?? [],
      }
    },
    SET_USER_INFO(state, data: UserInfo | null) {
      state.userInfo = data
    },
    SET_MEMBER_STATUS(state, data: MemberStatus | null) {
      state.memberStatus = data
    },
    SET_SHOW_SETTINGS(state, show: boolean) {
      state.showSettings = show
    },
    SET_SETTINGS_TAB(state, tab: string) {
      state.settingsTab = tab
    },
    SET_INVITE_CODE(state, code: string) {
      state.inviteCode = code
    },
    SET_SHOW_MEMBER_ACCESS_DIALOG(state, show: boolean) {
      state.showMemberAccessDialog = show
    },
    SET_PLUG_IS_ONLINE(state, online: boolean) {
      state.plugIsOnline = online
    },
    SET_PLUG_USE_VERSION(state, version: string) {
      state.plugUseVersion = version
      // 实时计算是否最新版本
      state.isLatestPlugin = version === state.plugTargetVersion
    },
  },
  actions: {
    updateAppName({ commit }, name: string) {
      commit('SET_APP_NAME', name)
    },
    openLogin({ commit }, redirect = '') {
      commit('SET_LOGIN_REDIRECT', redirect)
      commit('SET_SHOW_LOGIN', true)
    },
    closeLogin({ commit }) {
      commit('SET_SHOW_LOGIN', false)
      commit('SET_LOGIN_REDIRECT', '')
    },

    /**
     * 核心 action：从后端（或 mock）拉取菜单，转成路由并注册
     *
     * @param router — vue-router 实例，由路由守卫调用时传入
     *
     * 流程：
     *   1. 调 fetchUserRoutes 拿到后端菜单数据
     *   2. 存到 state.dynamicMenus（给 SideNav 渲染用）
     *   3. 用 buildDynamicRoutes 转成 RouteRecordRaw
     *   4. 逐条 router.addRoute 注册
     *   5. 记录已注册的路由名，标记 routesLoaded = true
     */
    async loadDynamicRoutes({ commit }, router: Router) {
      const menus = await fetchUserRoutes()
      commit('SET_DYNAMIC_MENUS', menus)

      const routes = buildDynamicRoutes(menus)
      const names: string[] = []

      for (const route of routes) {
        router.addRoute(route)
        if (route.name) names.push(route.name as string)
      }

      commit('SET_DYNAMIC_ROUTE_NAMES', names)
      commit('SET_ROUTES_LOADED', true)
    },

    /**
     * 静默刷新路由菜单数据（不重新注册路由，只更新菜单显示和权限状态）
     * 每次页面切换时由路由守卫调用，用于更新 accessible 权限信息
     */
    async refreshDynamicMenus({ commit }) {
      try {
        const menus = await fetchUserRoutes()
        commit('SET_DYNAMIC_MENUS', menus)
      } catch (err) {
        console.error('[store] 刷新路由菜单数据失败', err)
      }
    },

    /**
     * 登出：重置状态（不再操作 localStorage，登录状态由 Cookie 管理）
     * 注意：动态路由不清除，与登录状态无关
     */
    logout({ commit }) {
      commit('SET_AUTHENTICATED', false)
      commit('SET_SHOW_LOGIN', false)
      commit('SET_LOGIN_REDIRECT', '')
      commit('SET_USER_INFO', null)
      commit('SET_MEMBER_STATUS', null)
      // 清除 Jobs 页面缓存数据
      commit('SET_JOB_LIST_CACHE', null)
      commit('SET_JOB_INTENTION', {
        categoryIds: [],
        regionCodes: [],
        industryIds: [],
        employmentType: null,
        recruitCategory: null,
        aiCategoryIds: [],
        aiIndustryIds: [],
      })
    },

    /**
     * 加载工具类公共数据（行业分类、岗位分类等）
     * 进首页和 Jobs 页时调用
     * 如果 store 中已有数据则跳过请求，避免重复加载
     * 传入 force = true 可强制刷新
     */
    async loadCommonData({ commit, state }, { force = false } = {}) {
      const needIndustry = force || state.industries.length === 0
      const needJobCategory = force || state.jobCategories.length === 0
      const needRegion = force || state.regions.length === 0

      // 三个都已缓存，直接返回
      if (!needIndustry && !needJobCategory && !needRegion) return

      try {
        const promises: Promise<any>[] = []
        // 按需发起请求，保持顺序以便后续取值
        promises.push(needIndustry ? fetchIndustryTree() : Promise.resolve(null))
        promises.push(needJobCategory ? fetchJobCategoryTree() : Promise.resolve(null))
        promises.push(needRegion ? fetchRegionTree() : Promise.resolve(null))

        const [industryRes, jobCategoryRes, regionRes] = await Promise.all(promises)

        if (industryRes && industryRes.code === '0' && industryRes.data) {
          commit('SET_INDUSTRIES', industryRes.data)
        }
        if (jobCategoryRes && jobCategoryRes.code === '0' && jobCategoryRes.data) {
          commit('SET_JOB_CATEGORIES', jobCategoryRes.data)
        }
        if (regionRes && regionRes.code === '0' && regionRes.data) {
          commit('SET_REGIONS', regionRes.data)
        }
      } catch (err) {
        console.error('[store] 加载公共分类数据失败', err)
      }
    },

    /**
     * 从接口加载求职意向数据到 store
     * JobGoalDialog 和 Jobs 页面都可调用
     */
    async loadJobIntention({ commit }) {
      try {
        const res = await fetchJobIntention()
        if (res.code === '0' && res.data) {
          commit('SET_JOB_INTENTION', res.data)
        }
      } catch (err) {
        console.error('[store] 加载求职意向失败', err)
      }
    },

    /**
     * 加载用户个人信息到 store
     * 登录状态下调用，多个页面可直接读取 store.state.userInfo
     */
    async loadUserInfo({ commit }) {
      try {
        const res = await fetchUserInfo()
        if (res.code === '0' && res.data) {
          commit('SET_USER_INFO', res.data)
        }
      } catch (err) {
        console.error('[store] 加载用户信息失败', err)
      }
    },

    /**
     * 加载会员状态到 store
     * 登录状态下调用，多个页面可直接读取 store.state.memberStatus
     */
    async loadMemberStatus({ commit }) {
      try {
        const res = await fetchMemberStatus()
        if (res.code === '0' && res.data) {
          commit('SET_MEMBER_STATUS', res.data)
        }
      } catch (err) {
        console.error('[store] 加载会员状态失败', err)
      }
    },

    /**
     * 保存求职意向：已登录时调接口保存并更新 store，未登录时仅更新 store
     * @param data 求职意向数据
     */
    async saveJobIntention({ commit, state }, data: JobIntention) {
      if (state.isAuthenticated) {
        // 已登录 — 调接口持久化，成功后同步 store
        const res = await saveJobIntention(data)
        if (res.code === '0') {
          commit('SET_JOB_INTENTION', data)
        }
        return res
      } else {
        // 未登录 — 仅本地更新 store，不请求接口
        commit('SET_JOB_INTENTION', data)
        return { code: '0', message: 'ok' }
      }
    },

    /**
     * 初始化浏览器插件心跳监听
     * 双重检测机制：
     * 1. BroadcastChannel watch — 实时收心跳（插件与本页面同时在线时最快）
     * 2. 定时轮询 bridge.get 读 IndexedDB — 每3秒兜底检测（覆盖 BroadcastChannel 不通的场景）
     * 启动时立即 get 一次快速判断初始在线状态
     * 返回销毁函数
     */
    startPlugHeartbeat({ commit, state }) {
      const bridge = createChannelBridge({ domain: state.bridgeDomain })
      let lastHeartbeat = 0

      /** 解析 updateTime 字符串为时间戳（格式：yyyy-MM-dd HH:mm:ss） */
      function parseTime(timeStr: string): number {
        return new Date(timeStr.replace(' ', 'T')).getTime()
      }

      /** 根据 updateTime 判断是否在线并更新状态，同时提取 version */
      function checkOnline(updateTime: string, version?: string) {
        const elapsed = Date.now() - parseTime(updateTime)
        if (elapsed <= 3000) {
          lastHeartbeat = Date.now()
          if (!state.plugIsOnline) {
            commit('SET_PLUG_IS_ONLINE', true)
          }
          // 更新插件版本号
          if (version && version !== state.plugUseVersion) {
            commit('SET_PLUG_USE_VERSION', version)
          }
        }
      }

      // 启动时立即 get 一次，根据 updateTime 判断初始在线状态
      bridge.get<{ usage: string; version?: string }>(state.bridgeDomain, 'offerpieBrowserPlugUsage').then((data) => {
        if (data && data.updateTime) {
          checkOnline(data.updateTime, data.version)
        }
      })

      // 方式1：BroadcastChannel watch — 实时收心跳
      const unwatch = bridge.watch<{ usage: string; version?: string }>(
        state.bridgeDomain,
        'offerpieBrowserPlugUsage',
        (data) => {
          if (data && data.updateTime) {
            checkOnline(data.updateTime, data.version)
          }
        }
      )

      // 方式2：定时轮询 get IndexedDB — 兜底（覆盖 BroadcastChannel 断连场景）
      const pollTimer = setInterval(async () => {
        try {
          const data = await bridge.get<{ usage: string; version?: string }>(state.bridgeDomain, 'offerpieBrowserPlugUsage')
          if (data && data.updateTime) {
            checkOnline(data.updateTime, data.version)
          }
        } catch { /* 忽略读取异常 */ }
      }, 3000)

      // 定时检查超时（3秒无心跳判定离线）
      const checkTimer = setInterval(() => {
        if (lastHeartbeat > 0 && Date.now() - lastHeartbeat > 3000) {
          if (state.plugIsOnline) {
            commit('SET_PLUG_IS_ONLINE', false)
          }
        }
      }, 1000)

      // 返回销毁函数
      return () => {
        unwatch()
        clearInterval(pollTimer)
        clearInterval(checkTimer)
        bridge.destroy()
      }
    },
  },
  modules: {},
})
