<script setup lang="ts">
import { Bell, Fold, Search, SwitchButton } from '@element-plus/icons-vue';
import { ElMessage } from 'element-plus';
import { computed, onMounted, ref, watch } from 'vue';
import { RouterView, useRoute, useRouter } from 'vue-router';
import { http, type PageResult } from './api/http';
import AdminMenuTree from './components/AdminMenuTree.vue';
import { useAuthStore } from './stores/auth';
import { displayModelName, displayOperation, displayRole } from './utils/display';

interface AdminMenuNode {
  id: number;
  parentId: number;
  title: string;
  path?: string;
  icon?: string;
  sortOrder?: number;
  children?: AdminMenuNode[];
}

interface SearchOption {
  value: string;
  label: string;
  description: string;
  path: string;
  query?: Record<string, string>;
  type: '菜单' | '企业' | '员工' | '计费' | '待办';
}

interface ModulePageData {
  rows?: Record<string, any>[];
}

const route = useRoute();
const router = useRouter();
const auth = useAuthStore();
const collapsed = ref(false);
const menus = ref<AdminMenuNode[]>([]);
const searchKeyword = ref('');
const searchOptions = ref<SearchOption[]>([]);
const notifications = ref<SearchOption[]>([]);

const publicPage = computed(() => Boolean(route.meta.public));
const unreadCount = computed(() => notifications.value.length);

async function loadMenus() {
  if (!auth.isLoggedIn) {
    menus.value = [];
    return;
  }
  const currentMenus = await http.get<AdminMenuNode[]>('/menus/current');
  menus.value = normalizeMenuDepth(currentMenus);
}

onMounted(loadMenus);
watch(() => auth.token, loadMenus);
watch(
  () => route.path,
  () => {
    if (auth.isLoggedIn) loadNotifications();
  },
);

onMounted(() => {
  if (auth.isLoggedIn) loadNotifications();
});

function flattenMenus(nodes: AdminMenuNode[], trail: string[] = []): SearchOption[] {
  return nodes.flatMap((node) => {
    const label = [...trail, node.title].join(' / ');
    const current = node.path
      ? [{
          value: label,
          label: node.title,
          description: label,
          path: node.path,
          type: '菜单' as const,
        }]
      : [];
    return [...current, ...flattenMenus(node.children || [], [...trail, node.title])];
  });
}

function normalizeMenuDepth(nodes: AdminMenuNode[]): AdminMenuNode[] {
  const collectDescendantLinks = (children: AdminMenuNode[] = []): AdminMenuNode[] =>
    children.flatMap((child) => {
      const descendants = collectDescendantLinks(child.children || []);
      if (child.path) {
        return [{ ...child, children: [] }, ...descendants];
      }
      return descendants;
    });

  return nodes.map((node) => ({
    ...node,
    children: collectDescendantLinks(node.children || []),
  }));
}

function uniqueOptions(options: SearchOption[]) {
  const seen = new Set<string>();
  return options.filter((item) => {
    const key = `${item.type}:${item.path}:${item.label}:${JSON.stringify(item.query || {})}`;
    if (seen.has(key)) return false;
    seen.add(key);
    return true;
  });
}

async function buildSearchOptions(keyword: string) {
  const term = keyword.trim();
  const menuOptions = flattenMenus(menus.value)
    .filter((item) => !term || `${item.label}${item.description}`.toLowerCase().includes(term.toLowerCase()))
    .slice(0, 8);

  if (!term) {
    const quick = uniqueOptions([...notifications.value.slice(0, 4), ...menuOptions]).slice(0, 10);
    searchOptions.value = quick;
    return quick;
  }

  const [tenantPage, userPage, billingPage, warningPage, ticketPage, auditPage] = await Promise.allSettled([
    http.get<PageResult<Record<string, any>>>('/tenants', { params: { keyword: term, page: 1, size: 5 } }),
    http.get<PageResult<Record<string, any>>>('/users', { params: { keyword: term, page: 1, size: 5 } }),
    http.get<PageResult<Record<string, any>>>('/billing/records', { params: { keyword: term, page: 1, size: 5 } }),
    http.get<ModulePageData>('/module-pages/warnings'),
    http.get<ModulePageData>('/module-pages/tickets'),
    http.get<ModulePageData>('/module-pages/tenantAudits'),
  ]);

  const tenants = tenantPage.status === 'fulfilled' ? (tenantPage.value.records || []) : [];
  const users = userPage.status === 'fulfilled' ? (userPage.value.records || []) : [];
  const billings = billingPage.status === 'fulfilled' ? (billingPage.value.records || []) : [];
  const moduleRows = [warningPage, ticketPage, auditPage].flatMap((result) =>
    result.status === 'fulfilled' ? (result.value.rows || []) : [],
  );

  const containsTerm = (row: Record<string, any>) => JSON.stringify(row).toLowerCase().includes(term.toLowerCase());
  const options = uniqueOptions([
    ...menuOptions,
    ...tenants.map((row) => ({
      value: `企业 ${row.name || row.slug || row.id}`,
      label: row.name || row.slug || `企业 ${row.id}`,
      description: `${row.slug || '租户'} · ${row.plan || '套餐未设置'}`,
      path: row.id ? `/tenants/${row.id}` : '/tenants',
      type: '企业' as const,
    })),
    ...users.map((row) => ({
      value: `员工 ${row.username || row.email || row.id}`,
      label: row.username || row.email || `员工 ${row.id}`,
      description: `${row.email || row.phone || '账号信息'} · ${row.tenantName || row.tenant?.name || '组织员工'}`,
      path: '/users',
      query: { keyword: row.username || row.email || term },
      type: '员工' as const,
    })),
    ...billings.map((row) => ({
      value: `计费 ${row.refId || row.id}`,
      label: row.refId || `计费记录 ${row.id}`,
      description: `${row.modelName || row.modelId ? displayModelName(row.modelName, row.modelId) : displayOperation(row.operation)} · ${row.credits || 0} 积分`,
      path: '/billing/records',
      query: { keyword: row.refId || String(row.id || term) },
      type: '计费' as const,
    })),
    ...moduleRows.filter(containsTerm).slice(0, 6).map((row) => ({
      value: `待办 ${row.company || row.title || row.id || row.ticketNo}`,
      label: row.company || row.title || row.ticketNo || row.name || '业务待办',
      description: `${row.type || row.category || row.status || '待处理'} · ${row.reason || row.nextAction || row.summary || ''}`,
      path: row.ticketNo ? '/tickets' : row.type ? '/warnings' : '/tenant-audits',
      query: { keyword: row.company || row.title || row.ticketNo || term },
      type: '待办' as const,
    })),
  ]).slice(0, 14);

  searchOptions.value = options;
  return options;
}

async function loadNotifications() {
  if (!auth.isLoggedIn) return;
  const [auditPage, warningPage, ticketPage] = await Promise.allSettled([
    http.get<ModulePageData>('/module-pages/tenantAudits'),
    http.get<ModulePageData>('/module-pages/warnings'),
    http.get<ModulePageData>('/module-pages/tickets'),
  ]);
  const audits = auditPage.status === 'fulfilled' ? (auditPage.value.rows || []) : [];
  const warnings = warningPage.status === 'fulfilled' ? (warningPage.value.rows || []) : [];
  const tickets = ticketPage.status === 'fulfilled' ? (ticketPage.value.rows || []) : [];

  notifications.value = [
    ...audits
      .filter((row) => !['已通过', '已处理', '已关闭'].includes(row.status))
      .slice(0, 3)
      .map((row) => ({
        value: `审核 ${row.company || row.name}`,
        label: row.company || row.name || '入驻审核',
        description: row.riskConclusion || row.nextAction || row.status || '待复核企业资料',
        path: '/tenant-audits',
        query: { keyword: row.company || row.name },
        type: '待办' as const,
      })),
    ...warnings
      .filter((row) => !['已处理', '已关闭'].includes(row.status))
      .slice(0, 4)
      .map((row) => ({
        value: `预警 ${row.company || row.type}`,
        label: `${row.type || '运营预警'} · ${row.company || '未知企业'}`,
        description: row.reason || row.nextAction || row.status || '待处理预警',
        path: '/warnings',
        query: { keyword: row.company || row.type },
        type: '待办' as const,
      })),
    ...tickets
      .filter((row) => !['已处理', '已解决', '已关闭'].includes(row.status))
      .slice(0, 4)
      .map((row) => ({
        value: `工单 ${row.ticketNo || row.company}`,
        label: row.ticketNo || row.company || '客服工单',
        description: `${row.priority || '普通'} · ${row.category || row.status || '待跟进'}`,
        path: '/tickets',
        query: { keyword: row.ticketNo || row.company },
        type: '待办' as const,
      })),
  ].slice(0, 8);
}

function goSearch(item: SearchOption) {
  if (!item?.path) return;
  searchKeyword.value = '';
  router.push({ path: item.path, query: item.query });
}

async function submitSearch() {
  const keyword = searchKeyword.value.trim();
  if (!keyword) return;
  const options = await buildSearchOptions(keyword);
  const first = options[0];
  if (first) {
    goSearch(first);
    return;
  }
  ElMessage.info('没有找到匹配的企业、员工、计费记录或待办事项');
}

function openNotification(item: SearchOption) {
  router.push({ path: item.path, query: item.query });
}

async function logout() {
  await auth.logout();
  router.push('/auth/login');
}
</script>

<template>
  <RouterView v-if="publicPage" />
  <div v-else class="admin-shell">
    <aside class="side-rail" :class="{ collapsed }">
      <div class="brand-mark">
        <div class="brand-sigil">D</div>
        <div class="brand-copy">
          <b>Dramix</b>
          <span>Operations</span>
        </div>
      </div>
      <el-menu :default-active="route.path" router class="nav-menu" :collapse="collapsed" unique-opened>
        <AdminMenuTree :menus="menus" />
      </el-menu>
      <div class="side-footer">
        <span>运营额度</span>
        <strong>20,000</strong>
        <small>本地开发环境</small>
      </div>
    </aside>
    <main class="workbench">
      <header class="topbar">
        <div class="topbar-left">
          <el-button :icon="Fold" circle text @click="collapsed = !collapsed" />
          <span class="product-chip">总览</span>
          <span class="route-chip">{{ route.meta.title }}</span>
        </div>
        <div class="topbar-spacer"></div>
        <el-input
          v-model="searchKeyword"
          class="top-search"
          clearable
          placeholder="全局模糊搜索"
          @keyup.enter="submitSearch"
        >
          <template #prefix>
            <el-icon><Search /></el-icon>
          </template>
          <template #suffix>
            <el-button class="top-search-action" link type="primary" @click="submitSearch">搜索</el-button>
          </template>
        </el-input>
        <div class="operator">
          <el-popover placement="bottom-end" width="360" trigger="click" popper-class="notice-popper" @show="loadNotifications">
            <template #reference>
              <el-badge :value="unreadCount" :hidden="!unreadCount" :max="99">
                <el-button :icon="Bell" circle text aria-label="消息提醒" />
              </el-badge>
            </template>
            <div class="notice-panel">
              <header>
                <b>运营消息</b>
                <el-button link type="primary" @click="loadNotifications">刷新</el-button>
              </header>
              <div v-if="notifications.length" class="notice-list">
                <button v-for="item in notifications" :key="item.value" type="button" class="notice-item" @click="openNotification(item)">
                  <span>{{ item.label }}</span>
                  <small>{{ item.description }}</small>
                </button>
              </div>
              <el-empty v-else description="暂无待办消息" :image-size="72" />
            </div>
          </el-popover>
          <span>{{ auth.user?.displayName || auth.user?.username }}</span>
          <el-tag size="small" effect="plain">{{ displayRole(auth.role) }}</el-tag>
          <el-button :icon="SwitchButton" text @click="logout">退出</el-button>
        </div>
      </header>
      <section class="page-stage">
        <RouterView />
      </section>
    </main>
  </div>
</template>
