<script setup lang="ts">
import { api } from '@/utils/request'
import { useUserManageStore, type ScopeRecord } from '@/stores/user-manage'

interface ScopeTreeNode {
  key: string
  title: string
  children?: ScopeTreeNode[]
  isLeaf?: boolean
  scopeType?: 'company' | 'platform' | 'store'
  scopeId?: number
  rawTitle?: string
}

const props = defineProps<{
  open: boolean
  userId: number | null
  username: string
}>()

const emit = defineEmits<{
  'update:open': [value: boolean]
  saved: []
}>()

const store = useUserManageStore()

const loading = ref(false)
const saving = ref(false)
const scopeMode = ref<'company' | 'platform'>('company')
const searchValue = ref('')
const checkedKeys = ref<string[]>([])
const halfCheckedKeys = ref<string[]>([])
const expandedKeys = ref<string[]>([])
const autoExpandParent = ref(true)

// 基础数据列表
const companies = ref<{ id: number; name: string; label: string }[]>([])
const platforms = ref<{ id: number; name: string; label: string; developer_id: number }[]>([])
const storeList = ref<{ id: number; company_id: number; platform_id: number; name: string; label: string }[]>([])

const modeOptions = [
  { value: 'company', label: '按公司授权' },
  { value: 'platform', label: '按平台授权' },
]

// 名称查找辅助
function getCompanyName(id: number): string {
  const c = companies.value.find((x) => x.id === id)
  return c?.label || c?.name || `公司#${id}`
}

function getPlatformName(id: number): string {
  const p = platforms.value.find((x) => x.id === id)
  return p?.label || p?.name || `平台#${id}`
}

function getAllKeys(nodes: ScopeTreeNode[]): string[] {
  const keys: string[] = []
  for (const node of nodes) {
    keys.push(node.key)
    if (node.children) keys.push(...getAllKeys(node.children))
  }
  return keys
}

// 公司模式树：Company → [Platform] Store
const companyTree = computed<ScopeTreeNode[]>(() => {
  return companies.value.map((c) => {
    const label = c.label || c.name || `公司#${c.id}`
    const children = storeList.value
      .filter((s) => s.company_id === c.id)
      .map((s) => {
        const storeLabel = s.label || s.name || `店铺#${s.id}`
        const title = `[${getPlatformName(s.platform_id)}] ${storeLabel}`
        return {
          key: `store:${s.id}`,
          title,
          rawTitle: title,
          isLeaf: true,
          scopeType: 'store' as const,
          scopeId: s.id,
        }
      })
    return {
      key: `company:${c.id}`,
      title: label,
      rawTitle: label,
      scopeType: 'company' as const,
      scopeId: c.id,
      children,
    }
  })
})

// 平台模式树：Platform → [Company] Store
const platformTree = computed<ScopeTreeNode[]>(() => {
  return platforms.value
    .map((p) => {
      const label = p.label || p.name || `平台#${p.id}`
      const children = storeList.value
        .filter((s) => s.platform_id === p.id)
        .map((s) => {
          const storeLabel = s.label || s.name || `店铺#${s.id}`
          const title = `[${getCompanyName(s.company_id)}] ${storeLabel}`
          return {
            key: `store:${s.id}`,
            title,
            rawTitle: title,
            isLeaf: true,
            scopeType: 'store' as const,
            scopeId: s.id,
          }
        })
      return {
        key: `platform:${p.id}`,
        title: label,
        rawTitle: label,
        scopeType: 'platform' as const,
        scopeId: p.id,
        children,
      }
    })
    .filter((node) => node.children.length > 0)
})

const activeTree = computed(() =>
  scopeMode.value === 'company' ? companyTree.value : platformTree.value
)

const tipMessage = computed(() =>
  scopeMode.value === 'company'
    ? '勾选公司节点 = 授权其全部店铺；也可展开后仅勾选特定店铺'
    : '勾选平台节点 = 授权该平台全部店铺（跨公司）；也可展开后仅勾选特定店铺'
)

// 搜索高亮
function highlightParts(text: string, keyword: string): { text: string; highlight: boolean }[] {
  if (!keyword) return [{ text, highlight: false }]
  const lowerText = text.toLowerCase()
  const lowerKw = keyword.toLowerCase()
  const parts: { text: string; highlight: boolean }[] = []
  let lastIndex = 0
  let idx = lowerText.indexOf(lowerKw)
  while (idx !== -1) {
    if (idx > lastIndex) {
      parts.push({ text: text.slice(lastIndex, idx), highlight: false })
    }
    parts.push({ text: text.slice(idx, idx + keyword.length), highlight: true })
    lastIndex = idx + keyword.length
    idx = lowerText.indexOf(lowerKw, lastIndex)
  }
  if (lastIndex < text.length) {
    parts.push({ text: text.slice(lastIndex), highlight: false })
  }
  return parts
}

// 模式切换
function applyModeSwitch(mode: 'company' | 'platform') {
  scopeMode.value = mode
  checkedKeys.value = []
  halfCheckedKeys.value = []
  searchValue.value = ''
  expandedKeys.value = getAllKeys(activeTree.value)
}

function handleModeChange(val: unknown) {
  const newMode = val as 'company' | 'platform'
  if (checkedKeys.value.length > 0) {
    const oldMode = scopeMode.value
    Modal.confirm({
      title: '切换授权模式',
      content: '切换模式将清空当前选择，确认？',
      onOk() {
        applyModeSwitch(newMode)
      },
      onCancel() {
        // 强制刷新 segmented 受控值回弹
        scopeMode.value = oldMode
      },
    })
  } else {
    applyModeSwitch(newMode)
  }
}

// 树事件
function onCheck(
  checked: (string | number)[] | { checked: (string | number)[]; halfChecked: (string | number)[] },
  info: { halfCheckedKeys?: (string | number)[] },
) {
  const keys = Array.isArray(checked) ? checked : checked.checked
  checkedKeys.value = keys.map(String)
  const half = Array.isArray(checked) ? (info.halfCheckedKeys ?? []) : checked.halfChecked
  halfCheckedKeys.value = half.map(String)
}

function onExpand(keys: (string | number)[]) {
  expandedKeys.value = keys.map(String)
  autoExpandParent.value = false
}

// 初始模式检测
function detectInitialMode(userScopes: ScopeRecord[]): 'company' | 'platform' {
  const hasPlatform = userScopes.some((s) => s.scope_type === 'platform')
  const hasCompany = userScopes.some((s) => s.scope_type === 'company')
  if (hasPlatform && !hasCompany) return 'platform'
  return 'company'
}

// scopes → checkedKeys（父节点需补全子节点 key，受控模式不触发级联）
function scopesToCheckedKeys(userScopes: ScopeRecord[]): string[] {
  const keys: string[] = []
  const tree = activeTree.value
  for (const scope of userScopes) {
    if (scopeMode.value === 'company') {
      if (scope.scope_type === 'company') {
        const parentKey = `company:${scope.scope_id}`
        keys.push(parentKey)
        const node = tree.find((n) => n.key === parentKey)
        if (node?.children) keys.push(...node.children.map((c) => c.key))
      } else if (scope.scope_type === 'store') {
        keys.push(`store:${scope.scope_id}`)
      }
    } else {
      if (scope.scope_type === 'platform') {
        const parentKey = `platform:${scope.scope_id}`
        keys.push(parentKey)
        const node = tree.find((n) => n.key === parentKey)
        if (node?.children) keys.push(...node.children.map((c) => c.key))
      } else if (scope.scope_type === 'store') {
        keys.push(`store:${scope.scope_id}`)
      }
    }
  }
  return keys
}

// checkedKeys → scopes（智能判断全选/部分选）
function checkedKeysToScopes(): Omit<ScopeRecord, 'name'>[] {
  const scopes: Omit<ScopeRecord, 'name'>[] = []
  const keySet = new Set(checkedKeys.value)

  for (const key of checkedKeys.value) {
    const [type, idStr] = key.split(':')
    const id = Number(idStr)
    if (!type || Number.isNaN(id)) continue

    if (scopeMode.value === 'company') {
      if (type === 'company') {
        scopes.push({ scope_type: 'company', scope_id: id })
      } else if (type === 'store') {
        const s = storeList.value.find((x) => x.id === id)
        if (s && !keySet.has(`company:${s.company_id}`)) {
          scopes.push({ scope_type: 'store', scope_id: id })
        }
      }
    } else {
      if (type === 'platform') {
        scopes.push({ scope_type: 'platform', scope_id: id })
      } else if (type === 'store') {
        const s = storeList.value.find((x) => x.id === id)
        if (s && !keySet.has(`platform:${s.platform_id}`)) {
          scopes.push({ scope_type: 'store', scope_id: id })
        }
      }
    }
  }

  return scopes
}

function handleClose() {
  emit('update:open', false)
}

async function loadEntities() {
  try {
    const [c, p, s] = await Promise.all([
      api.get<typeof companies.value>('/api/v1/companies'),
      api.get<typeof platforms.value>('/api/v1/platforms'),
      api.get<typeof storeList.value>('/api/v1/stores'),
    ])
    companies.value = c
    platforms.value = p
    storeList.value = s
  } catch (err: unknown) {
    const msg = err instanceof Error ? err.message : '加载基础数据失败'
    message.error(msg)
  }
}

async function loadData() {
  if (!props.userId) return
  loading.value = true
  try {
    const [scopeData] = await Promise.allSettled([
      store.fetchUserDataScope(props.userId),
      loadEntities(),
    ])
    if (scopeData.status === 'fulfilled') {
      const userScopes = scopeData.value.scopes
      scopeMode.value = detectInitialMode(userScopes)
      await nextTick()
      checkedKeys.value = scopesToCheckedKeys(userScopes)
    } else {
      checkedKeys.value = []
    }
    expandedKeys.value = getAllKeys(activeTree.value)
  } finally {
    loading.value = false
  }
}

async function handleSave() {
  if (!props.userId) return
  const validScopes = checkedKeysToScopes()
  saving.value = true
  try {
    await store.saveUserDataScope(props.userId, validScopes)
    message.success('数据范围保存成功')
    emit('saved')
    handleClose()
  } catch (err: unknown) {
    const msg = err instanceof Error ? err.message : '保存失败'
    message.error(msg)
  } finally {
    saving.value = false
  }
}

// 搜索时自动展开匹配节点的父级
watch(searchValue, (val) => {
  if (!val) {
    expandedKeys.value = getAllKeys(activeTree.value)
    return
  }
  const matched: string[] = []
  const findParents = (nodes: ScopeTreeNode[], parents: string[]) => {
    for (const node of nodes) {
      if (node.rawTitle?.toLowerCase().includes(val.toLowerCase())) {
        matched.push(...parents)
      }
      if (node.children) {
        findParents(node.children, [...parents, node.key])
      }
    }
  }
  findParents(activeTree.value, [])
  expandedKeys.value = [...new Set(matched)]
  autoExpandParent.value = true
})

watch(
  () => props.open,
  (val) => {
    if (val) {
      loadData()
    } else {
      checkedKeys.value = []
      halfCheckedKeys.value = []
      searchValue.value = ''
      scopeMode.value = 'company'
    }
  },
  { immediate: true },
)
</script>

<template>
  <a-modal
    :open="open"
    :title="`数据范围 - ${username}`"
    width="720px"
    :confirm-loading="saving"
    @cancel="handleClose"
    @ok="handleSave"
  >
    <a-spin :spinning="loading">
      <!-- 模式切换 -->
      <a-segmented
        :value="scopeMode"
        :options="modeOptions"
        class="mb-3"
        @change="handleModeChange"
      />

      <!-- 提示 -->
      <a-alert type="info" show-icon :message="tipMessage" class="mb-3" />

      <!-- 搜索 -->
      <a-input-search
        v-model:value="searchValue"
        placeholder="搜索名称"
        allow-clear
        class="mb-3"
      />

      <!-- 空状态 -->
      <a-empty v-if="activeTree.length === 0 && !loading" description="暂无可授权的数据" />

      <!-- 树 -->
      <div v-else style="max-height: 400px; overflow-y: auto;">
        <a-tree
          :checked-keys="checkedKeys"
          checkable
          :tree-data="activeTree"
          :selectable="false"
          :expanded-keys="expandedKeys"
          :auto-expand-parent="autoExpandParent"
          @check="onCheck"
          @expand="onExpand"
        >
          <template #title="{ dataRef }">
            <template
              v-if="searchValue && dataRef.rawTitle?.toLowerCase().includes(searchValue.toLowerCase())"
            >
              <span
                v-for="(part, i) in highlightParts(dataRef.rawTitle, searchValue)"
                :key="i"
              >
                <span v-if="part.highlight" class="text-red-500 font-semibold">{{
                  part.text
                }}</span>
                <span v-else>{{ part.text }}</span>
              </span>
            </template>
            <span v-else>{{ dataRef.rawTitle || dataRef.title }}</span>
          </template>
        </a-tree>
      </div>
    </a-spin>
  </a-modal>
</template>
