<script lang="ts" setup>
/**
 * 管理端基础布局：铃铛站内信轮询 + 动作宿主挂载
 */
import type { NotificationItem } from '@vben/layouts';

import { computed, onUnmounted, ref, watch } from 'vue';
import { useRouter } from 'vue-router';

import { AuthenticationLoginExpiredModal, VbenIcon } from '@vben/common-ui';
import { useWatermark } from '@vben/hooks';
import { $t } from '@vben/locales';
import {
  BasicLayout,
  LockScreen,
  Notification,
  UserDropdown,
} from '@vben/layouts';
import { preferences, usePreferences } from '@vben/preferences';
import { useAccessStore, useUserStore } from '@vben/stores';

import { notification } from 'ant-design-vue';
import { Bell, Users } from 'lucide-vue-next';

import DoctorTransferFloat from '#/components/doctor-transfer-float/DoctorTransferFloat.vue';
import HeaderVipBadge from '#/components/vip/HeaderVipBadge.vue';
import SwitchAccountModal from '#/layouts/components/SwitchAccountModal.vue';
import { useAuthStore } from '#/store';
import { desktop, isElectron } from '#/util/desktop';
import { formatTimeToRelative } from '#/util/tool';
import LoginForm from '#/views/_core/authentication/login.vue';
import NoticeActionHost from '#/views/notice/action/NoticeActionHost.vue';
import {
  emitNoticeRefresh,
  onNoticeRefresh,
  openNoticeAction,
} from '#/views/notice/action/bus';
import { resolveNoticeColor } from '#/views/notice/action/types';
import {
  getNoticeListApi,
  getNoticeUnreadCountApi,
  readAllApi,
  readApi,
} from '#/views/notice/api';

const router = useRouter();
const switchAccountModalRef = ref<InstanceType<typeof SwitchAccountModal>>();
const notifications = ref<NotificationItem[]>([]);
const unreadCount = ref(0);

/** 拉取未读列表 + 角标数字 */
const getNoticeList = async () => {
  try {
    const [res, countRes] = await Promise.all([
      getNoticeListApi({ status: 0, page: 1, pageSize: 20 }),
      getNoticeUnreadCountApi().catch(() => null),
    ]);
    const items = res?.items || [];
    const prevLen = notifications.value.length;
    if (items.length > prevLen && prevLen > 0) {
      notification.info({
        message: '您有新消息',
        description: `您有 ${items.length} 条未读消息请注意查收`,
        duration: 5,
      });
      // 桌面端且窗口未聚焦时补发系统通知（页内 Toast 此时用户看不到），点击跳消息中心
      if (isElectron() && !document.hasFocus()) {
        desktop.notify({
          title: '您有新消息',
          body: `您有 ${items.length} 条未读消息请注意查收`,
          route: '/notice/list',
        });
        desktop.flashFrame();
      }
    }
    notifications.value = items.map((item: any) => {
      const color = resolveNoticeColor(item.type_color);
      return {
        id: item.id,
        // Notification 默认用组件当 icon；我们走自定义 content 槽，这里占位即可
        icon: Bell as any,
        message: item.detail || item.type_name || '',
        title: item.title || '通知',
        date: formatTimeToRelative(item.created_at),
        color: color.text,
        colorBg: color.bg,
        isRead: Number(item.status) === 1,
        status: item.status,
        type_code: item.type_code,
        type_name: item.type_name,
        type_icon: item.type_icon,
        type_color: item.type_color,
        action_type: item.action_type,
        action_payload: item.action_payload,
        detail: item.detail,
        content: item.content,
        edit_type: item.edit_type,
        priority: item.priority,
        raw: item,
      };
    });
    unreadCount.value = Number(
      countRes?.count ?? res?.unread_total ?? items.length,
    );
  } catch (error) {
    console.error('获取消息列表失败:', error);
  }
};
getNoticeList();
let intervalId = setInterval(getNoticeList, 20_000);

const restartInterval = () => {
  clearInterval(intervalId);
  getNoticeList();
  intervalId = setInterval(getNoticeList, 20_000);
};

const handleStorageChange = (event: StorageEvent) => {
  if (event.key === 'readStatus') {
    restartInterval();
  }
};

const originalSetItem = localStorage.setItem.bind(localStorage);
localStorage.setItem = (key, value) => {
  originalSetItem(key, value);
  if (key === 'readStatus') {
    restartInterval();
  }
};

window.addEventListener('storage', handleStorageChange);
const stopRefreshListen = onNoticeRefresh(() => restartInterval());

// 桌面端：未读数变化同步任务栏/Dock 角标（浏览器环境 no-op）
watch(unreadCount, (count) => desktop.setBadge(count));

// 桌面端：系统通知点击后主进程回传目标路由，这里执行实际跳转
desktop.onNavigate((route) => {
  router.push(route);
});

// 桌面端：自动更新事件轻量提示（下载完成后的安装确认由主进程弹窗负责）
desktop.onUpdateEvent((payload) => {
  if (payload.type === 'available') {
    const version = (payload.data as { version?: string })?.version;
    notification.info({
      message: '发现新版本',
      description: `新版本 ${version ? `v${version} ` : ''}正在后台下载，完成后将提示安装`,
      duration: 5,
    });
  }
});

onUnmounted(() => {
  clearInterval(intervalId);
  window.removeEventListener('storage', handleStorageChange);
  localStorage.setItem = originalSetItem;
  stopRefreshListen();
  // 布局卸载（登出）时清空桌面角标，避免残留未读数
  desktop.setBadge(0);
  // 解绑系统通知跳转回调，避免登出后点击残留通知仍对已登出会话执行 router.push
  desktop.offNavigate();
});

const goNoticeList = () => {
  router.push('/notice/list');
};

/** 从铃铛列表移除并扣减角标 */
function removeFromBell(item: NotificationItem) {
  notifications.value = notifications.value.filter((n) => n.id !== item.id);
  unreadCount.value = Math.max(0, unreadCount.value - 1);
}

/** 行点击：立刻取消未读并打开场景 */
const handleItemClick = async (item: NotificationItem) => {
  const raw = (item as any).raw || item;
  const wasUnread = !item.isRead;
  item.isRead = true;
  if (wasUnread) {
    removeFromBell(item);
  }
  await openNoticeAction({
    ...raw,
    id: item.id,
    status: wasUnread ? 0 : 1,
  });
};

const handleClick = async (item: NotificationItem) => {
  await handleItemClick(item);
};

/** 勾选已读：只标已读，不打开详情 */
async function handleMarkRead(item: NotificationItem) {
  if (item.isRead) return;
  item.isRead = true;
  removeFromBell(item);
  try {
    await readApi(Number(item.id));
    emitNoticeRefresh();
  } catch {
    /* ignore */
  }
}

const userStore = useUserStore();
const authStore = useAuthStore();
const accessStore = useAccessStore();
const { destroyWatermark, updateWatermark } = useWatermark();
const { isDark } = usePreferences();
const showDot = computed(() => unreadCount.value > 0);

const showDoctorTransfer = computed(() => {
  const info = userStore.userInfo as Record<string, any> | null | undefined;
  if (!info) return false;
  return !!(info.doctor_id && info.store_id);
});

const menus = computed(() => [
  {
    handler: () => {
      router.push({ name: 'Profile' });
    },
    icon: 'lucide:user',
    text: $t('page.auth.profile'),
  },
  {
    handler: () => {
      switchAccountModalRef.value?.openModal();
    },
    icon: Users,
    text: '切换账号',
  },
]);

const avatar = computed(() => {
  return userStore.userInfo?.avatar ?? preferences.app.defaultAvatar;
});

async function handleLogout() {
  await authStore.logout(false);
  destroyWatermark();
}

function handleNoticeClear() {
  readAllApi().then(() => {
    notifications.value = [];
    unreadCount.value = 0;
    notification.success({
      message: '标记成功',
      duration: 2,
    });
    emitNoticeRefresh();
  });
}

/** 全部已读：必须走后端 API */
function handleMakeAll() {
  readAllApi().then(() => {
    notifications.value = [];
    unreadCount.value = 0;
    notification.success({
      message: '标记成功',
      duration: 2,
    });
  });
}

watch(
  () => ({
    enable: preferences.app.watermark,
    isDark: isDark.value,
  }),
  async ({ enable }) => {
    if (enable) {
      await updateWatermark({
        content: `${userStore.userInfo?.nick_name}\r\n${userStore.userInfo?.phone || import.meta.env.VITE_APP_TITLE}`,
      });
    } else {
      destroyWatermark();
    }
  },
  { immediate: true },
);
</script>

<template>
  <BasicLayout
    :avatar
    :text="userStore.userInfo?.realName"
    @clear-preferences-and-logout="handleLogout"
    @logout="handleLogout"
  >
    <template #header-right-55>
      <DoctorTransferFloat v-if="showDoctorTransfer" />
    </template>
    <template #user-dropdown>
      <!-- VIP 徽标放在头像左侧，与用户下拉并排 -->
      <div class="flex items-center">
        <HeaderVipBadge />
        <UserDropdown
          :avatar
          :menus
          :text="userStore.userInfo?.nick_name"
          :description="userStore.userInfo?.email"
          :tag-text="userStore.userInfo?.roles?.name"
          @clear-preferences-and-logout="handleLogout"
          @logout="handleLogout"
        />
      </div>
    </template>
    <template #notification>
      <Notification
        :dot="showDot"
        :count="unreadCount"
        :notifications="notifications"
        @clear="handleNoticeClear"
        @make-all="handleMakeAll"
        @read="handleMarkRead"
        @view-all="goNoticeList"
        @on-click="handleClick"
      >
        <template #content="{ item }">
          <span
            v-if="!item.isRead"
            class="absolute top-2 right-2 size-2 rounded-sm bg-primary"
          ></span>
          <span
            class="relative flex size-10 shrink-0 items-center justify-center overflow-hidden rounded-xl"
            :class="[(item as any).colorBg || 'bg-muted', (item as any).color]"
          >
            <VbenIcon
              v-if="(item as any).type_icon"
              :icon="(item as any).type_icon"
              class="size-5"
            />
            <Bell v-else class="size-5" />
          </span>
          <div class="min-w-0 flex-1 pr-8 leading-none">
            <div class="mb-1 flex items-center gap-2">
              <span
                v-if="(item as any).type_name"
                class="truncate text-[11px] font-semibold"
                :class="(item as any).color"
              >
                {{ (item as any).type_name }}
              </span>
            </div>
            <p class="truncate text-sm font-semibold text-foreground">
              {{ item.title }}
            </p>
            <p
              v-if="item.message"
              class="mt-1 line-clamp-2 text-xs text-muted-foreground"
            >
              {{ item.message }}
            </p>
            <p class="mt-1 text-xs text-muted-foreground">{{ item.date }}</p>
          </div>
        </template>
      </Notification>
      <NoticeActionHost />
    </template>
    <template #extra>
      <AuthenticationLoginExpiredModal
        v-model:open="accessStore.loginExpired"
        :avatar
      >
        <LoginForm />
      </AuthenticationLoginExpiredModal>
      <SwitchAccountModal ref="switchAccountModalRef" />
    </template>
    <template #lock-screen>
      <LockScreen :avatar @to-login="handleLogout" />
    </template>
  </BasicLayout>
</template>
