import { defineStore } from 'pinia'
import { computed, reactive, ref } from 'vue'
import { system } from '@repo/api-service'

import { resolveMenuRoutePath } from '@/config/menu'
import type { PermissionMenuNode } from '@/types/permission'

const ROOT_MENU_CODE = 'aiRoot'

const isRecord = (value: unknown): value is Record<string, unknown> =>
	typeof value === 'object' && value !== null

const toStringValue = (value: unknown) => (typeof value === 'string' ? value : '')

const toNumberValue = (value: unknown) => (typeof value === 'number' ? value : 0)

const readMenuChildren = (value: unknown) => {
	if (!Array.isArray(value)) return []
	return value.filter(isRecord)
}

// 后端 leftMenu 返回字段较多，这里只保留权限判断和侧边栏渲染需要的字段。
const normalizeMenuNode = (node: unknown): PermissionMenuNode => ({
	code: isRecord(node) ? toStringValue(node.code) : '',
	name: isRecord(node) ? toStringValue(node.name) || toStringValue(node.langName) : '',
	langName: isRecord(node) ? toStringValue(node.langName) : '',
	link: isRecord(node) ? toStringValue(node.link) : '',
	menuIndex: isRecord(node) ? toNumberValue(node.menuIndex) : 0,
	menuType: isRecord(node) ? toNumberValue(node.menuType) : 0,
	openType: isRecord(node) ? toNumberValue(node.openType) : 0,
	children: isRecord(node) ? readMenuChildren(node.subMenuList).map(normalizeMenuNode) : []
})

const flattenMenuTree = (menus: PermissionMenuNode[]): PermissionMenuNode[] =>
	menus.flatMap((menu) => [menu, ...flattenMenuTree(menu.children)])

export const usePermissionStore = defineStore('permissionStore', () => {
	const rootMenu = ref<PermissionMenuNode | null>(null)
	const initialized = ref(false)
	const initializing = ref(false)
	// 以菜单编码为 key 缓存按钮权限，避免同一页面重复请求授权按钮列表。
	const buttonPermissions = reactive<Record<string, string[]>>({})

	// 合并并发初始化请求，避免路由守卫和 Sidebar 同时触发重复加载。
	let initializePromise: Promise<void> | null = null
	const buttonPermissionPromises = new Map<string, Promise<string[]>>()

	const menuTree = computed(() => rootMenu.value?.children || [])
	const flatMenus = computed(() => flattenMenuTree(menuTree.value))
	const authorisedMenuCodes = computed(() => new Set(flatMenus.value.map((menu) => menu.code)))

	const resetPermissionState = () => {
		rootMenu.value = null
		initialized.value = false
		initializing.value = false
		Object.keys(buttonPermissions).forEach((menuCode) => {
			delete buttonPermissions[menuCode]
		})
		buttonPermissionPromises.clear()
		initializePromise = null
	}

	// 拉取 aiRoot 下的授权菜单树，是菜单显示和路由权限判断的基础数据。
	const initializePermissions = async (force = false) => {
		if (initialized.value && !force) return
		if (initializePromise && !force) return initializePromise

		if (force) {
			resetPermissionState()
		}

		initializing.value = true
		initializePromise = (async () => {
			const response = await system.postMenuLeftMenuList({
				menuCode: ROOT_MENU_CODE
			})

			rootMenu.value = normalizeMenuNode(response?.result || {})
			initialized.value = true
			initializing.value = false
		})()

		try {
			await initializePromise
		} finally {
			initializePromise = null
			initializing.value = false
		}
	}

	const hasMenuAccess = (menuCode?: string) => {
		if (!menuCode) return true
		return authorisedMenuCodes.value.has(menuCode)
	}

	const getButtonPermissions = (menuCode?: string) => {
		if (!menuCode) return []
		return buttonPermissions[menuCode] || []
	}

	// 按菜单懒加载按钮权限，匹配接口返回的 result: string[]，如 ['add', 'edit']。
	const ensureButtonPermissions = async (menuCode?: string, force = false) => {
		if (!menuCode) return []
		if (!hasMenuAccess(menuCode)) return []

		if (!force && buttonPermissions[menuCode]) {
			return buttonPermissions[menuCode]
		}

		const existingPromise = buttonPermissionPromises.get(menuCode)
		if (existingPromise && !force) {
			return existingPromise
		}

		const requestPromise = (async () => {
			const response = await system.postMenubuttonAuthorised({ menuCode })
			const result = Array.isArray(response?.result) ? response.result : []
			buttonPermissions[menuCode] = result
			return result
		})()

		buttonPermissionPromises.set(menuCode, requestPromise)

		try {
			return await requestPromise
		} finally {
			buttonPermissionPromises.delete(menuCode)
		}
	}

	const hasButtonAccess = (menuCode: string | undefined, buttonCode: string) => {
		if (!menuCode || !buttonCode) return false
		return getButtonPermissions(menuCode).includes(buttonCode)
	}

	// 当前访问无权限时，回退到用户有权限且前端已配置路由的第一个菜单。
	const getFirstAccessibleRoutePath = () => {
		for (const menu of flatMenus.value) {
			const path = resolveMenuRoutePath(menu.code)
			if (path) return path
		}

		return '/'
	}

	return {
		rootMenu,
		menuTree,
		flatMenus,
		authorisedMenuCodes,
		initialized,
		initializing,
		initializePermissions,
		hasMenuAccess,
		getButtonPermissions,
		ensureButtonPermissions,
		hasButtonAccess,
		getFirstAccessibleRoutePath,
		resetPermissionState
	}
})
