<script setup lang="ts">
import type { MenuProps } from 'antdv-next';

import { computed, h, onBeforeUnmount, onMounted, ref, watch } from 'vue';

import {
  loadLocaleMessages,
  type SupportedLanguagesType,
} from '@velofex/locales';
import { preferences, updatePreferences } from '@velofex/preferences';
import { TabsView } from '@velofex-core/tabs-ui';

import {
  curUserInfo,
  type curUserInfoPayload,
  leftMenuListFromB,
} from '@/api/account';
import defaultCompanyLogo from '@/assets/image/earth_18301626@2x.png';
import defaultAvatar from '@/assets/image/user.png';
import { resolveEnterpriseCodeFromLocation } from '@/router/guard';
import { Dropdown, Menu } from 'antdv-next';

import SelectLang from '#/components/select-lang.vue';
import { $t } from '#/locales';

const leftMenuItems = ref<MenuProps['items']>([]);
const selectedKeys = ref<string[]>([]);
const userMenuItems = computed<MenuProps['items']>(() => [
  { key: 'ChangeInformation', label: $t('home.userMenu.changeInformation') },
  { key: 'Logout', label: $t('home.userMenu.logout') },
]);
const openMenuKeys = ref<string[]>([]);
const isMobileSidebarOpen = ref(false);
const userInfo = ref<curUserInfoPayload>();
const pageTitle = ref('');
const pageCrumb = ref('');
const menuMetaByKey = ref<
  Record<string, { crumb: string; iframeSrc: string; title: string }>
>({});
const iframeTabs = ref<
  Array<{ crumb: string; iframeSrc: string; key: string; title: string }>
>([]);
const activeTabKey = ref('');
const companyLogoSrc = ref('/Content/Images/company-logo.png');
const avatarSrc = computed(() => {
  const avatar = userInfo.value?.avatar;
  return avatar ? `/File/Download?fileId=${avatar}` : defaultAvatar;
});
const contentTabs = computed(() => {
  return iframeTabs.value.map((tab) => {
    return {
      fullPath: tab.key,
      meta: {
        tabClosable: true,
        title: tab.title,
      },
      name: tab.title,
      path: tab.key,
    } as any;
  });
});

function handleCompanyLogoError() {
  companyLogoSrc.value = defaultCompanyLogo;
}

type RawMenuNode = {
  code?: string;
  deleted?: boolean;
  fullName?: string;
  icon?: string;
  iconClass?: string;
  iconColor?: string;
  id?: string;
  isDeleted?: boolean;
  link?: string;
  name?: string;
  subMenuList?: RawMenuNode[];
};

function buildMenuIframeSrc(link?: string, id?: string) {
  const linkPart = String(link ?? '').trim();
  if (!linkPart) {
    return '';
  }

  const idPart = String(id ?? '').trim();
  const addMenuIdQuery = (url: string) => {
    if (!idPart) {
      return url;
    }

    const hashIndex = url.indexOf('#');
    const pathAndQuery = hashIndex === -1 ? url : url.slice(0, hashIndex);
    const hashPart = hashIndex === -1 ? '' : url.slice(hashIndex);
    const joiner = pathAndQuery.includes('?') ? '&' : '?';
    return `${pathAndQuery}${joiner}menuId=${idPart}${hashPart}`;
  };

  if (/^https?:\/\//i.test(linkPart)) {
    return addMenuIdQuery(linkPart);
  }

  const normalizedPath = linkPart.startsWith('/') ? linkPart : `/${linkPart}`;
  return addMenuIdQuery(normalizedPath);
}

function normalizeMenuIconClass(iconClass?: string) {
  if (!iconClass) {
    return [];
  }

  return iconClass
    .replaceAll(',', ' ')
    .split(' ')
    .map((token) => token.trim())
    .filter(Boolean);
}

function renderMenuLabel(node: RawMenuNode, fallbackText: string) {
  const iconClass = node.iconClass || node.icon;
  const text = node.name || node.fullName || fallbackText;
  const normalizedIconClass = normalizeMenuIconClass(iconClass);

  if (normalizedIconClass.length === 0) {
    return text;
  }

  return h('span', { class: 'menu-node-label' }, [
    h('i', {
      class: ['menu-node-icon', ...normalizedIconClass],
    }),
    h('span', { class: 'menu-node-text' }, text),
  ]);
}

function mapMenuItems(
  nodes: RawMenuNode[],
  firstLeafPathRef: string[],
  parentPath: string[] = [],
  parentLabelPath: string[] = [],
  metaMap: Record<
    string,
    { crumb: string; iframeSrc: string; title: string }
  > = {},
): NonNullable<MenuProps['items']> {
  return nodes
    .filter((node) => !(node.deleted || node.isDeleted))
    .map((node, index) => {
      const key = node.id || node.code || `${node.name ?? 'menu'}-${index}`;
      const labelText = node.name || node.fullName || key;
      const currentPath = [...parentPath, key];
      const currentLabelPath = [...parentLabelPath, labelText];
      metaMap[key] = {
        crumb: currentLabelPath.join(' / '),
        iframeSrc: buildMenuIframeSrc(node.link, node.id),
        title: labelText,
      };
      const children = mapMenuItems(
        node.subMenuList ?? [],
        firstLeafPathRef,
        currentPath,
        currentLabelPath,
        metaMap,
      );

      if (children.length === 0 && firstLeafPathRef.length === 0) {
        firstLeafPathRef.push(...currentPath);
      }

      return {
        key,
        label: renderMenuLabel(node, key),
        children: children.length > 0 ? children : undefined,
      };
    });
}

function applyMenuMeta(key: string) {
  const meta = menuMetaByKey.value[key];
  if (!meta) {
    pageTitle.value = '';
    pageCrumb.value = '';
    return;
  }
  pageTitle.value = meta.title;
  pageCrumb.value = meta.crumb;
}

function clearActiveTab() {
  activeTabKey.value = '';
  selectedKeys.value = [];
  pageTitle.value = '';
  pageCrumb.value = '';
}

function setActiveTab(key: string) {
  activeTabKey.value = key;
  selectedKeys.value = [key];
  applyMenuMeta(key);
}

function openIframeTab(key: string) {
  const meta = menuMetaByKey.value[key];
  if (!meta?.iframeSrc) {
    return;
  }

  const nextTab = {
    crumb: meta.crumb,
    iframeSrc: meta.iframeSrc,
    key,
    title: meta.title,
  };
  const existingIndex = iframeTabs.value.findIndex((tab) => tab.key === key);

  if (existingIndex === -1) {
    iframeTabs.value.push(nextTab);
  } else {
    iframeTabs.value.splice(existingIndex, 1, nextTab);
  }

  setActiveTab(key);
}

async function loadLeftMenuFromB() {
  const { result } = await leftMenuListFromB();
  const firstLeafPath: string[] = [];
  const nextMetaMap: Record<
    string,
    { crumb: string; iframeSrc: string; title: string }
  > = {};
  const items = mapMenuItems(
    result?.subMenuList ?? [],
    firstLeafPath,
    [],
    [],
    nextMetaMap,
  );

  menuMetaByKey.value = nextMetaMap;
  iframeTabs.value = iframeTabs.value.flatMap((tab) => {
    const meta = nextMetaMap[tab.key];
    if (!meta?.iframeSrc) {
      return [];
    }

    return [
      {
        crumb: meta.crumb,
        iframeSrc: meta.iframeSrc,
        key: tab.key,
        title: meta.title,
      },
    ];
  });

  leftMenuItems.value = items;
  if (firstLeafPath.length > 0) {
    const defaultKey = firstLeafPath[firstLeafPath.length - 1]!;
    openMenuKeys.value = items
      .filter(
        (item) =>
          item &&
          (item as any).children &&
          Array.isArray((item as any).children) &&
          (item as any).children.length > 0,
      )
      .map((item) => String(item!.key));

    if (activeTabKey.value && nextMetaMap[activeTabKey.value]?.iframeSrc) {
      setActiveTab(activeTabKey.value);
    } else if (iframeTabs.value.length > 0) {
      setActiveTab(iframeTabs.value[0]!.key);
    } else {
      openIframeTab(defaultKey);
    }
  } else {
    openMenuKeys.value = [];
    iframeTabs.value = [];
    clearActiveTab();
  }
}

async function getCurUserInfo() {
  const { result } = await curUserInfo();
  userInfo.value = result;
}

let isRefreshingData = false;
let refreshQueued = false;
let isApplyingLocaleFromUserInfo = false;
let hasInitializedLanguageFromUserInfo = false;

function resolveLocaleByUserLanguage(
  language?: string,
): null | SupportedLanguagesType {
  const value = String(language ?? '').trim();
  if (value === 'en' || value === 'en-US') {
    return 'en-US';
  }
  if (value === 'zh-CN' || value === 'zh') {
    return 'zh-CN';
  }
  return null;
}

async function refreshHomeData() {
  if (isRefreshingData) {
    refreshQueued = true;
    return;
  }

  isRefreshingData = true;
  do {
    refreshQueued = false;
    await getCurUserInfo();

    if (!hasInitializedLanguageFromUserInfo) {
      const localeFromUserInfo = resolveLocaleByUserLanguage(
        userInfo.value?.language,
      );
      if (localeFromUserInfo && localeFromUserInfo !== preferences.app.locale) {
        isApplyingLocaleFromUserInfo = true;
        try {
          updatePreferences({
            app: {
              locale: localeFromUserInfo,
            },
          });
          await loadLocaleMessages(localeFromUserInfo);
        } finally {
          isApplyingLocaleFromUserInfo = false;
        }
      }
      hasInitializedLanguageFromUserInfo = true;
    }

    await loadLeftMenuFromB();
  } while (refreshQueued);
  isRefreshingData = false;
}

function handleLocaleStorageChange(event: StorageEvent) {
  if (!event.key?.endsWith('-preferences-locale')) {
    return;
  }
  if (event.newValue === event.oldValue) {
    return;
  }
  void refreshHomeData();
}

onMounted(async () => {
  await refreshHomeData();
  window.addEventListener('storage', handleLocaleStorageChange);
});

onBeforeUnmount(() => {
  window.removeEventListener('storage', handleLocaleStorageChange);
});

watch(
  () => preferences.app.locale,
  (locale, previousLocale) => {
    if (locale === previousLocale || isApplyingLocaleFromUserInfo) {
      return;
    }
    void refreshHomeData();
  },
);

function handleMenuOpenChange(keys: string[]) {
  openMenuKeys.value = keys;
}

function handleLeftMenuClick({ key }: { key: string }) {
  const normalizedKey = String(key);
  openIframeTab(normalizedKey);
  closeMobileSidebar();
}

function handleTabChange(key: string) {
  const normalizedKey = String(key);
  if (!menuMetaByKey.value[normalizedKey]) {
    return;
  }

  setActiveTab(normalizedKey);
}

function handleTabClose(key: string) {
  const normalizedKey = String(key);
  const currentIndex = iframeTabs.value.findIndex(
    (tab) => tab.key === normalizedKey,
  );
  if (currentIndex === -1) {
    return;
  }

  iframeTabs.value.splice(currentIndex, 1);
  if (activeTabKey.value !== normalizedKey) {
    return;
  }

  const nextActiveTab =
    iframeTabs.value[currentIndex] ??
    iframeTabs.value[currentIndex - 1] ??
    null;
  if (nextActiveTab) {
    setActiveTab(nextActiveTab.key);
    return;
  }

  clearActiveTab();
}

function handleSortTabs(oldIndex: number, newIndex: number) {
  if (oldIndex === newIndex) {
    return;
  }

  const nextTabs = [...iframeTabs.value];
  const movedTabs = nextTabs.splice(oldIndex, 1);
  const movedTab = movedTabs[0];
  if (!movedTab) {
    return;
  }

  nextTabs.splice(newIndex, 0, movedTab);
  iframeTabs.value = nextTabs;
}

function openMobileSidebar() {
  isMobileSidebarOpen.value = true;
}

function closeMobileSidebar() {
  isMobileSidebarOpen.value = false;
}

function handleUserMenuClick({ key }: { key: string }) {
  if (key === 'ChangeInformation' && window.top && window.top !== window) {
    window.top.location.href = '/user-profile';
  }

  if (key === 'Logout') {
    const enterpriseCode = resolveEnterpriseCodeFromLocation();
    // if (enterpriseCode) {
    //   localStorage.removeItem(`token_${enterpriseCode}`);
    // }

    const logoutUrl = `/Account/Logout?enterpriseCode=${enterpriseCode}`;
    try {
      if (window.top && window.top !== window) {
        window.top.location.href = logoutUrl;
        return;
      }
    } catch {}

    window.location.href = logoutUrl;
  }
}
</script>

<template>
  <div class="enterprise-page">
    <div
      :class="[{ show: isMobileSidebarOpen }]"
      class="mobile-mask"
      @click="closeMobileSidebar"
    ></div>
    <div class="enterprise-shell">
      <aside
        :class="[{ 'mobile-open': isMobileSidebarOpen }]"
        class="left-panel"
      >
        <div class="brand-card">
          <div class="logo-dot">
            <img :src="companyLogoSrc" @error="handleCompanyLogoError" />
          </div>
          <div class="brand-text">{{ userInfo?.enterpriseName }}</div>
          <button
            class="mobile-close-btn"
            type="button"
            @click="closeMobileSidebar"
          >
            x
          </button>
        </div>

        <div class="menu-scroll-wrap">
          <Menu
            :items="leftMenuItems"
            :open-keys="openMenuKeys"
            :selected-keys="selectedKeys"
            class="enterprise-menu"
            mode="inline"
            @click="(info: any) => handleLeftMenuClick(info)"
            @open-change="handleMenuOpenChange"
          />
        </div>
      </aside>

      <section class="right-panel">
        <header class="top-bar">
          <div class="title-wrap">
            <div class="crumb">{{ pageCrumb }}</div>
          </div>

          <div class="top-actions">
            <button
              class="mobile-toggle-btn"
              type="button"
              @click="openMobileSidebar"
            >
              Menu
            </button>
            <SelectLang />
            <Dropdown
              :menu="{
                items: userMenuItems,
              }"
              placement="bottom"
              @menu-click="(info: any) => handleUserMenuClick(info)"
            >
              <div class="user-avatar cursor-pointer">
                <img :src="avatarSrc" alt="avatar" />
              </div>
            </Dropdown>
          </div>
        </header>

        <div class="content-placeholder">
          <template v-if="iframeTabs.length > 0">
            <div class="content-tabs-wrap">
              <TabsView
                :active="activeTabKey"
                :draggable="preferences.tabbar.draggable"
                :show-icon="false"
                :style-type="preferences.tabbar.styleType"
                :tabs="contentTabs"
                :wheelable="preferences.tabbar.wheelable"
                @close="handleTabClose"
                @sort-tabs="handleSortTabs"
                @update:active="handleTabChange"
              />
            </div>

            <div class="content-iframe-stack">
              <iframe
                v-for="tab in iframeTabs"
                v-show="tab.key === activeTabKey"
                :key="tab.key"
                :src="tab.iframeSrc"
                border="0"
                class="content-iframe"
              ></iframe>
            </div>
          </template>

          <div v-else class="content-empty">暂无可显示内容</div>
        </div>
      </section>
    </div>
  </div>
</template>

<style scoped lang="scss">
@media (width <= 960px) {
  .enterprise-page {
    padding: 10px;
  }

  .enterprise-shell {
    flex-direction: column;
    min-height: calc(100vh - 20px);
  }

  .left-panel {
    position: fixed;
    inset: 0 auto 0 0;
    width: 280px;
    border-right: 1px solid #efebf1;
    transition: transform 0.24s ease;
    transform: translateX(-100%);
  }

  .left-panel.mobile-open {
    transform: translateX(0);
  }

  .mobile-close-btn {
    display: block;
  }

  .right-panel {
    padding: 20px 16px;
    margin: 0;
    border-radius: 0;
    box-shadow: none;
  }

  .right-panel::before {
    border-radius: 0;
  }

  .top-bar {
    flex-direction: column;
    gap: 12px;
    align-items: flex-start;
  }

  .mobile-toggle-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
}

.enterprise-page {
  height: 100vh;
  min-height: 100vh;
  overflow: hidden;
  background: radial-gradient(
      circle at 78% 88%,
      rgb(193 233 255 / 35%),
      transparent 36%
    ),
    radial-gradient(circle at 70% 92%, rgb(255 216 199 / 30%), transparent 30%),
    #f2f0f3;
}

.enterprise-shell {
  display: flex;
  height: 100vh;
  min-height: 100vh;
  overflow: hidden;
  background: #f8f6f8;
  box-shadow: 0 10px 30px rgb(60 34 51 / 8%);
}

.mobile-mask {
  position: fixed;
  inset: 0;
  z-index: 20;
  pointer-events: none;
  background: rgb(26 15 23 / 42%);
  opacity: 0;
  transition: opacity 0.2s ease;
}

.mobile-mask.show {
  pointer-events: auto;
  opacity: 1;
}

.left-panel {
  position: relative;
  z-index: 30;
  display: flex;
  flex-direction: column;
  width: 256px;
  height: 100%;
  min-height: 0;
  padding: 24px 16px;
  overflow: hidden;
  background: #f8f6f8;
  border-right: none;
}

.menu-scroll-wrap {
  flex: 1;
  min-height: 0;
  padding-right: 4px;
  overflow-y: auto;
  scrollbar-color: #cbb8c3 transparent;
  scrollbar-width: thin;
}

.menu-scroll-wrap::-webkit-scrollbar {
  width: 3px;
}

.menu-scroll-wrap::-webkit-scrollbar-thumb {
  background-color: #cbb8c3;
  border-radius: 999px;
}

.menu-scroll-wrap::-webkit-scrollbar-track {
  background: transparent;
}

.brand-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: center;
  padding-bottom: 20px;
  margin-bottom: 18px;
  border-bottom: 1px solid #ece6ed;
}

.mobile-close-btn {
  display: none;
  width: 28px;
  height: 28px;
  margin-left: auto;
  font-size: 12px;
  line-height: 1;
  color: #7a4860;
  background: #fff;
  border: 1px solid #d8cbd5;
  border-radius: 6px;
}

.logo-dot {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;

  img {
    width: 100%;
    height: 100%;
    object-fit: contain;
  }
}

.brand-text {
  font-size: 14px;
  font-weight: 600;
  color: #4f4250;
}

.user-avatar {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;

  img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
}

:deep(.enterprise-menu) {
  background: transparent;
  border-inline-end: none;
}

:deep(.enterprise-menu .ant-menu-item) {
  height: auto;
  padding: 9px 10px;
  margin: 0 0 6px;
  font-size: 13px;
  line-height: 1.2;
  color: #6f6771;
  border-radius: 8px;
}

:deep(.menu-node-label) {
  display: inline-flex;
  gap: 8px;
  align-items: center;
  font-size: 16px;
}

:deep(.menu-node-icon) {
  font-size: 14px;
  line-height: 1;
  color: currentcolor;
}

:deep(.enterprise-menu .ant-menu-item-selected) {
  font-weight: 600;
  color: #fff;
  background: #8b1648;
}

:deep(.enterprise-menu .ant-menu-item-selected .menu-node-icon),
:deep(.enterprise-menu .ant-menu-item-selected .menu-node-text) {
  color: #fff !important;
}

:deep(.enterprise-menu .ant-menu-submenu-selected > .ant-menu-submenu-title) {
  color: #5a4f5a;
  background: transparent;
}

:deep(.enterprise-menu .ant-menu-item-selected::after) {
  display: none;
}

:deep(.enterprise-menu .ant-menu-sub .ant-menu-item) {
  font-size: 12px;
}

:deep(.ant-menu-light.ant-menu-root.ant-menu-inline) {
  border-inline-end: none;
}

:deep(.ant-menu-light.ant-menu-inline .ant-menu-sub.ant-menu-inline) {
  background: none;
}

:deep(.enterprise-menu .ant-menu-submenu-title) {
  height: auto;
  padding: 8px 10px;
  margin: 0 0 6px;
  font-size: 13px;
  font-weight: 600;
  color: #5a4f5a;
  border-radius: 8px;
}

:deep(.enterprise-menu .ant-menu-submenu-title:hover) {
  color: #5a4f5a;
}

:deep(.content-tabs-wrap .vben-tabs-content) {
  height: 100%;
}

:deep(.content-tabs-wrap .tabs-chrome) {
  height: 100%;
  padding-right: 4px;
}

:deep(.content-tabs-wrap .tabs-chrome__item-main) {
  min-width: 72px;
}

:deep(.content-tabs-wrap [data-radix-scroll-area-viewport]) {
  overflow-y: hidden !important;
  scrollbar-width: none;
}

:deep(.content-tabs-wrap [data-radix-scroll-area-viewport]::-webkit-scrollbar) {
  height: 0;
}

:deep(.content-tabs-wrap [data-orientation='horizontal'].hidden) {
  display: flex !important;
}

:deep(.content-tabs-wrap [data-orientation='horizontal']) {
  height: 6px;
  padding: 0 2px;
  opacity: 0;
  transition: opacity 0.2s ease;
}

:deep(
  .content-tabs-wrap [data-orientation='horizontal'][data-state='visible']
) {
  opacity: 1;
}

:deep(.content-tabs-wrap [data-orientation='horizontal'] .bg-border) {
  background: rgb(139 22 72 / 50%) !important;
}

:deep(.content-tabs-wrap .is-active .tabs-chrome__background-content) {
  background: rgb(139 22 72 / 10%) !important;
}

:deep(.content-tabs-wrap .is-active .text-sm) {
  color: rgb(139 22 72) !important;
}

:deep(.content-tabs-wrap .is-active .tabs-chrome__background-before),
:deep(.content-tabs-wrap .is-active .tabs-chrome__background-after) {
  fill: rgb(139 22 72 / 10%) !important;
}

:deep(.overflow-y-hidden) {
  overflow: hidden;
}

.right-panel {
  position: relative;
  display: flex;
  flex: 1;
  flex-direction: column;
  padding: 28px 32px;
  overflow: hidden;
  border-radius: 50px 0 0 50px;
  box-shadow: 0 8px 20px rgb(95 67 84 / 10%);
}

.right-panel::before {
  position: absolute;
  inset: 0;
  z-index: 0;
  content: '';
  background: #fff;
}

.right-panel > * {
  position: relative;
  z-index: 1;
}

.top-bar {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  padding-bottom: 16px;
  border-bottom: 1px solid #f0ebf1;
}

.title-wrap {
  display: flex;
  flex-direction: row;
  align-items: baseline;
}

.crumb {
  margin-left: 8px;
  font-size: 20px;
  color: #3e2b33;
}

.top-actions {
  display: flex;
  gap: 10px;
  align-items: center;
}

.mobile-toggle-btn {
  display: none;
  height: 32px;
  padding: 0 12px;
  font-size: 12px;
  color: #6f4e60;
  background: #fff;
  border: 1px solid #dcced7;
  border-radius: 16px;
}

.content-placeholder {
  display: flex;
  flex: 1;
  flex-direction: column;
  min-height: 0;
  margin-top: 12px;
  overflow: hidden;
  background: #fff;
}

.content-tabs-wrap {
  flex-shrink: 0;
  height: 42px;
  padding: 0 10px;
  overflow: hidden;
  background: linear-gradient(180deg, #fcfafc 0%, #f7f3f6 100%);
  border-bottom: 1px solid #f0ebf1;
}

.content-iframe-stack {
  position: relative;
  flex: 1;
  min-height: 0;
}

.content-iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

.content-empty {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  font-size: 14px;
  color: #8b808a;
}
</style>
