import type { ImGroupRequestApi } from '#/api/im/group/request'

import { acceptHMRUpdate, defineStore } from 'pinia'

import { agreeGroupRequest as apiAgreeGroupRequest, getMyGroupRequest as apiGetMyGroupRequest, getUnhandledRequestList as apiGetUnhandledRequestList, pullMyGroupRequestList as apiPullMyGroupRequestList, refuseGroupRequest as apiRefuseGroupRequest } from '#/api/im/group/request'
import { getCurrentUserId } from '#/views/im/utils/auth'
import { ImGroupRequestHandleResult } from '#/views/im/utils/constants'

import { getDb, StorageKeys } from '../../utils/db'
import { runIncrementalPull } from '../../utils/pull'

type PendingRequest = { epoch: number; promise: Promise<void>; userId: number; }

/** clear() 时递增；旧账号 in-flight 的 pullGroupRequests 结果 resolve 后比对一致才写 store，防跨账号红点污染（与 friendStore 同口径） */
let storeEpoch = 0
let pendingUnhandledFetch: null | PendingRequest = null

/**
 * IM 加群申请 Store
 *
 * 仅维护「我管理的所有群」下未处理的申请列表（unhandledList）；
 * 横幅 / Drawer 都从这里派生 count 和分组列表，避免给 ImGroupApi.GroupRespVO 挂 pendingRequestCount 字段
 *
 * 数据生命周期：
 * - 进 IM 后调一次 fetchUnhandledGroupRequestList 拉首页全量
 * - WebSocket 1503 → 调 addGroupRequestById(requestId) 拉单条 + push 到 unhandledList 头部
 * - WebSocket 1505 / 1506 → 按 requestId 从 unhandledList 移除
 * - WebSocket 1517 GROUP_ADMIN_ADD（自己被加为 admin）→ 重新调 fetchUnhandledGroupRequestList
 * - 本端 agree / refuse 处理后 → 本地按 requestId 移除
 */
export const useGroupRequestStore = defineStore('imGroupRequestStore', {
  state: () => ({
    /** 我管理的所有群下未处理申请列表（按 id 倒序） */
    unhandledList: [] as ImGroupRequestApi.GroupRequestRespVO[],
    /** fetchUnhandledGroupRequestList 是否成功执行过；避免横幅显示 0 然后跳数字的闪烁 */
    loaded: false
  }),

  getters: {
    /**
     * 各群下未处理申请数的 Map；O(N) 扫一次缓存供 ConversationItem 等 N 处复用，避免 N×M 重复 filter
     */
    getUnhandledGroupRequestCountMap(state): Map<number, number> {
      const map = new Map<number, number>()
      for (const request of state.unhandledList) {
        map.set(request.groupId, (map.get(request.groupId) ?? 0) + 1)
      }
      return map
    },
    /** 指定群下的未处理申请数 */
    getUnhandledGroupRequestCount(): (groupId: number) => number {
      return (groupId: number) => this.getUnhandledGroupRequestCountMap.get(groupId) ?? 0
    },
    /** 指定群下的未处理申请列表 */
    getUnhandledGroupRequestListByGroupId:
      (state) =>
      (groupId: number): ImGroupRequestApi.GroupRequestRespVO[] =>
        state.unhandledList.filter((r) => r.groupId === groupId)
  },

  actions: {
    /** 从 IndexedDB 恢复加群申请 */
    async loadGroupRequestList(): Promise<boolean> {
      try {
        const cached = await getDb().getAll<ImGroupRequestApi.GroupRequestRespVO>('groupRequests')
        if (!cached || cached.length === 0) {
          return false
        }
        this.unhandledList = cached
          .filter((request) => request.handleResult === ImGroupRequestHandleResult.UNHANDLED)
          .toSorted((requestA, requestB) => requestB.id - requestA.id)
        return true
      } catch (error) {
        console.warn('[IM groupRequestStore] 本地加群申请缓存读取失败', error)
        return false
      }
    },

    /** 保存加群申请列表 */
    saveGroupRequestList(): void {
      void getDb()
        .transaction(['groupRequests'], 'readwrite', async (tx) => {
          const db = getDb()
          await db.clearStore('groupRequests', tx)
          for (const request of this.unhandledList) {
            await db.put('groupRequests', request, tx)
          }
        })
        .catch((error) => console.warn('[IM groupRequestStore] 本地加群申请缓存写入失败', error))
    },

    /** 保存单条加群申请 */
    async saveGroupRequestRecord(request: ImGroupRequestApi.GroupRequestRespVO): Promise<void> {
      await getDb().put('groupRequests', request)
    },

    /** 保存单条加群申请 */
    saveGroupRequest(request: ImGroupRequestApi.GroupRequestRespVO): void {
      void this.saveGroupRequestRecord(request).catch((error) =>
        console.warn('[IM groupRequestStore] 本地加群申请写入失败', error)
      )
    },

    /** 拉取我管理的所有群下未处理申请；进 IM 后 / 升级 admin 后 / WS 推送有冲突时调用 */
    async fetchUnhandledGroupRequestList() {
      const requestEpoch = storeEpoch
      const requestUserId = getCurrentUserId()
      if (
        pendingUnhandledFetch?.epoch === requestEpoch &&
        pendingUnhandledFetch.userId === requestUserId
      ) {
        return pendingUnhandledFetch.promise
      }
      const promise = (async () => {
        const list = await apiGetUnhandledRequestList()
        if (requestEpoch !== storeEpoch || getCurrentUserId() !== requestUserId) {
          return
        }
        this.unhandledList = list || []
        this.loaded = true
        this.saveGroupRequestList()
      })().finally(() => {
        if (
          pendingUnhandledFetch?.epoch === requestEpoch &&
          pendingUnhandledFetch.userId === requestUserId
        ) {
          pendingUnhandledFetch = null
        }
      })
      pendingUnhandledFetch = { epoch: requestEpoch, userId: requestUserId, promise }
      return promise
    },

    /**
     * WS 收到 1503：拉最新内容并置顶
     *
     * 同一对 group_id, user_id 复用记录时 requestId 不变但 applyContent / inviterUserId 会刷新，所以无条件 fetch + 排到头部
     */
    async addGroupRequestById(requestId: number) {
      const requestEpoch = storeEpoch
      const requestUserId = getCurrentUserId()
      const request = await apiGetMyGroupRequest(requestId)
      if (!request) {
        return
      }
      if (requestEpoch !== storeEpoch || getCurrentUserId() !== requestUserId) {
        return
      }
      this.upsertGroupRequest(request)
    },

    /**
     * 本地合并 / 新增单条加群申请（WS 推送 & 增量拉取共用）
     *
     * 未处理的按 id 去重后置顶；已处理的从未处理列表移除，避免补偿时把已同意 / 拒绝的记录塞回红点
     */
    upsertGroupRequest(request: ImGroupRequestApi.GroupRequestRespVO) {
      void this.upsertGroupRequestForPull(request).catch((error) =>
        console.warn('[IM groupRequestStore] 本地加群申请写入失败', error)
      )
    },

    /** 本地合并 / 新增单条加群申请 */
    async upsertGroupRequestForPull(request: ImGroupRequestApi.GroupRequestRespVO): Promise<void> {
      if (request.handleResult !== ImGroupRequestHandleResult.UNHANDLED) {
        await this.removeGroupRequestByIdForPull(request.id)
        return
      }
      this.unhandledList = [request, ...this.unhandledList.filter((r) => r.id !== request.id)]
      await this.saveGroupRequestRecord(request)
    },

    /**
     * 增量拉取加群申请变更并合并；含已处理的按 handleResult 走移除（已处理 → 从红点列表剔除）
     *
     * 只做重连 / 后续离线补偿，不负责首登：首登红点走 fetchUnhandledGroupRequestList（服务端直接过滤未处理，语义更精准、启动更轻）。
     * 故首次重连时游标为空 = 一次性全量走一遍（已处理记录命中 removeGroupRequestById 为 no-op，红点不受影响），之后增量。
     */
    async pullGroupRequests() {
      // 快照 epoch；账号在拉取途中切换（clear() → epoch++）时丢弃旧账号那几页结果，防跨账号红点污染
      const requestEpoch = storeEpoch
      const requestUserId = getCurrentUserId()
      const isActive = () => requestEpoch === storeEpoch && getCurrentUserId() === requestUserId
      await runIncrementalPull(
        StorageKeys.settings.groupRequestPullCursor,
        apiPullMyGroupRequestList,
        async (records) => {
          if (!isActive()) {
            return false
          }
          await Promise.all(records.map((vo) => this.upsertGroupRequestForPull(vo)))
          return true
        },
        isActive
      )
      if (isActive()) {
        this.loaded = true
      }
    },

    /** WS 收到 1505 / 1506 或本端处理完一条：按 requestId 从列表移除 */
    removeGroupRequestById(requestId: number) {
      this.unhandledList = this.unhandledList.filter((r) => r.id !== requestId)
      void getDb()
        .delete('groupRequests', requestId)
        .catch((error) => console.warn('[IM groupRequestStore] 本地加群申请删除失败', error))
    },

    /** 删除单条加群申请 */
    async removeGroupRequestByIdForPull(requestId: number): Promise<void> {
      this.unhandledList = this.unhandledList.filter((r) => r.id !== requestId)
      await getDb().delete('groupRequests', requestId)
    },

    /** 同意申请；本端处理后立即从列表移除，避免被反复点击 */
    async agreeGroupRequest(requestId: number) {
      await apiAgreeGroupRequest(requestId)
      this.removeGroupRequestById(requestId)
    },

    /** 拒绝申请 */
    async refuseGroupRequest(requestId: number, handleContent?: string) {
      await apiRefuseGroupRequest(requestId, handleContent)
      this.removeGroupRequestById(requestId)
    },

    /** 清空加群申请内存 */
    clear() {
      this.unhandledList = []
      this.loaded = false
      // 账号切换：递增 epoch 废弃旧账号 in-flight 的 pullGroupRequests 结果，避免写进新账号红点列表
      storeEpoch++
      pendingUnhandledFetch = null
    }
  }
})

export const useGroupRequestStoreWithOut = () => useGroupRequestStore()

if (import.meta.hot) {
  import.meta.hot.accept(acceptHMRUpdate(useGroupRequestStore, import.meta.hot))
}
