<script setup lang="ts">
import { ReloadOutlined, SearchOutlined } from "@ant-design/icons-vue";
import { useQuery } from "@tanstack/vue-query";
import type { DesktopAccountInfo, MediaPlatform } from "@geo/shared-types";
import { computed, ref } from "vue";
import { useI18n } from "vue-i18n";

import { mediaApi, resolveApiURL, tenantAccountsApi } from "@/lib/api";
import { resolveAccountCheckedAt, resolveAccountHealth } from "@/lib/desktop-account-runtime";
import { formatDateTime } from "@/lib/display";
import { getPublishPlatformMeta, isPublishPlatformId, normalizePublishPlatformId } from "@/lib/publish-platforms";

type AccountHealthFilter = "all" | "live" | "captcha" | "risk" | "expired";
type PublishState = "immediate" | "queued" | "unavailable";

interface MediaAccountCard {
  id: string;
  platform: string;
  platformLabel: string;
  platformShortName: string;
  platformAccent: string;
  platformLogoUrl: string | null;
  displayName: string;
  platformUid: string;
  avatarUrl: string | null;
  health: DesktopAccountInfo["health"];
  verifiedAt: string | null;
  clientId: string | null;
  clientOnline: boolean | null;
  clientDeviceName: string | null;
  clientLastSeenAt: string | null;
  publishState: PublishState;
  publishHint: string;
  deleteRequestedAt: string | null;
}

const platformLogoCatalog: Record<string, string> = {
  toutiaohao: "/logos/logo_toutiao.png",
  baijiahao: "/logos/logo_baijiahao.png",
  sohuhao: "/logos/logo_souhu.png",
  qiehao: "/logos/logo_qiehao.png",
  zhihu: "/logos/logo_zhihu.png",
  wangyihao: "/logos/logo_wangyihao.png",
  jianshu: "/logos/logo_jianshu.svg",
  bilibili: "/logos/logo_bilibili.png",
  juejin: "/logos/logo_juejin.png",
  smzdm: "/logos/logo_smzdm.svg",
  weixin_gzh: "/logos/logo_weixin_gzh.svg",
  zol: "/logos/logo_zol.png",
  dongchedi: "/logos/logo_dongchedi.svg",
};

const { t } = useI18n();

const searchQuery = ref("");
const selectedHealth = ref<AccountHealthFilter>("all");

const platformsQuery = useQuery({
  queryKey: ["media", "platforms", "media-view"],
  queryFn: () => mediaApi.platforms(),
});

const accountsQuery = useQuery({
  queryKey: ["tenant", "desktop-accounts", "media-view"],
  queryFn: () => tenantAccountsApi.list(),
});

const loading = computed(() => platformsQuery.isPending.value || accountsQuery.isPending.value);
const refreshing = computed(() => platformsQuery.isFetching.value || accountsQuery.isFetching.value);

const platformMap = computed(() => {
  return new Map(
    (platformsQuery.data.value ?? []).map((platform: MediaPlatform) => [
      normalizePublishPlatformId(platform.platform_id),
      platform,
    ]),
  );
});

const mediaAccounts = computed<MediaAccountCard[]>(() => {
  return [...(accountsQuery.data.value ?? [])]
    .filter((account) => !account.deleted_at)
    .filter((account) => isPublishPlatformId(account.platform))
    .map((account) => {
      const platformId = normalizePublishPlatformId(account.platform);
      const platform = platformMap.value.get(platformId);
      const fallback = getPublishPlatformMeta(platformId);
      const publishState = resolvePublishState(account);
      const health = resolveAccountHealth(account);

      return {
        id: account.id,
        platform: platformId,
        platformLabel: platform?.name || fallback.name,
        platformShortName: platform?.short_name || fallback.shortName,
        platformAccent: platform?.accent_color || fallback.accent,
        platformLogoUrl: resolvePlatformLogoUrl(platformId, platform?.logo_url),
        displayName: account.display_name,
        platformUid: normalizePlatformUid(account.platform_uid),
        avatarUrl: resolveApiURL(account.avatar_url),
        health,
        verifiedAt: resolveAccountCheckedAt(account),
        clientId: account.client_id,
        clientOnline: account.client_online,
        clientDeviceName: account.client_device_name,
        clientLastSeenAt: account.client_last_seen_at,
        publishState,
        publishHint: resolvePublishHint(account, publishState),
        deleteRequestedAt: account.delete_requested_at,
      };
    })
    .sort((left, right) => {
      const publishGap = publishRank(left.publishState) - publishRank(right.publishState);
      if (publishGap !== 0) {
        return publishGap;
      }

      const leftAt = Date.parse(left.verifiedAt ?? "") || 0;
      const rightAt = Date.parse(right.verifiedAt ?? "") || 0;
      return rightAt - leftAt;
    });
});

const overview = computed(() => ({
  total: mediaAccounts.value.length,
  live: mediaAccounts.value.filter((item) => item.health === "live").length,
  immediate: mediaAccounts.value.filter((item) => item.publishState === "immediate").length,
  queued: mediaAccounts.value.filter((item) => item.publishState === "queued").length,
  attention: mediaAccounts.value.filter((item) => item.publishState === "unavailable").length,
}));

const filteredAccounts = computed(() => {
  const keyword = searchQuery.value.trim().toLowerCase();

  return mediaAccounts.value.filter((account) => {
    if (selectedHealth.value !== "all" && account.health !== selectedHealth.value) {
      return false;
    }

    if (!keyword) {
      return true;
    }

    return [
      account.displayName,
      account.platformLabel,
      account.platformUid,
      account.clientDeviceName ?? "",
    ].join(" ").toLowerCase().includes(keyword);
  });
});

function resolvePublishState(account: DesktopAccountInfo): PublishState {
  if (resolveAccountHealth(account) !== "live") {
    return "unavailable";
  }
  if (!account.client_id) {
    return "unavailable";
  }
  return account.client_online === true ? "immediate" : "queued";
}

function resolvePublishHint(account: DesktopAccountInfo, publishState: PublishState): string {
  if (publishState === "immediate") {
    return "";
  }
  if (publishState === "queued") {
    return "客户端当前离线，任务会先进入发布队列，等桌面端上线后自动继续。";
  }
  if (resolveAccountHealth(account) !== "live") {
    return "授权状态异常，先在桌面端重新校验后再发布。";
  }
  return "还没有绑定桌面客户端，当前无法加入发布队列。";
}

function normalizePlatformUid(value?: string | null): string {
  let normalized = String(value ?? "").trim();
  while (normalized.toLowerCase().startsWith("platform:")) {
    normalized = normalized.slice("platform:".length).trim();
  }
  return normalized || "--";
}

function resolvePlatformLogoUrl(platformId: string, remoteLogoUrl?: string | null): string | null {
  const localLogoUrl = platformLogoCatalog[platformId];
  if (localLogoUrl) {
    return localLogoUrl;
  }

  const resolvedRemoteLogoUrl = resolveApiURL(remoteLogoUrl);
  return resolvedRemoteLogoUrl || null;
}

function accountInitial(account: MediaAccountCard): string {
  const name = account.displayName.trim();
  return name ? name.slice(0, 1).toUpperCase() : account.platformShortName;
}

function publishRank(state: PublishState): number {
  switch (state) {
    case "immediate":
      return 0;
    case "queued":
      return 1;
    default:
      return 2;
  }
}

function healthLabel(health: DesktopAccountInfo["health"]): string {
  switch (health) {
    case "live":
      return "授权正常";
    case "captcha":
      return "待处理";
    case "risk":
      return "风险观察";
    default:
      return "授权异常";
  }
}

function healthColor(health: DesktopAccountInfo["health"]): string {
  switch (health) {
    case "live":
      return "green";
    case "captcha":
      return "orange";
    case "risk":
      return "gold";
    default:
      return "red";
  }
}

function clientStatusLabel(account: MediaAccountCard): string {
  if (!account.clientId) {
    return "未绑定";
  }
  return account.clientOnline ? "在线" : "离线";
}

function clientStatusColor(account: MediaAccountCard): string {
  if (!account.clientId) {
    return "default";
  }
  return account.clientOnline ? "green" : "gold";
}

function clientStatusText(account: MediaAccountCard): string {
  if (!account.clientId) {
    return "未绑定桌面客户端";
  }

  const device = account.clientDeviceName?.trim();
  return device ? `${clientStatusLabel(account)} · ${device}` : clientStatusLabel(account);
}

function publishStateLabel(state: PublishState): string {
  switch (state) {
    case "immediate":
      return "可立即发布";
    case "queued":
      return "离线排队";
    default:
      return "不可发布";
  }
}

function publishStateColor(state: PublishState): string {
  switch (state) {
    case "immediate":
      return "green";
    case "queued":
      return "gold";
    default:
      return "red";
  }
}

async function refreshAll(): Promise<void> {
  await Promise.all([
    platformsQuery.refetch(),
    accountsQuery.refetch(),
  ]);
}
</script>

<template>
  <div class="media-view">
    <section class="media-view__top-card">
      <div class="media-view__header">
        <div class="media-view__header-title">
          <h2>{{ t("route.media.title") }}</h2>
          <p>这里展示 `platform_accounts` 里当前用户已绑定的桌面媒体账号，以及它们是否能立即发布、离线排队或需要处理。</p>
        </div>
        <div class="media-view__header-actions">
          <a-button :loading="refreshing" @click="refreshAll">
            <template #icon><ReloadOutlined /></template>
            刷新状态
          </a-button>
        </div>
      </div>

      <div class="overview-strip border-t">
        <div class="overview-chip">
          <span>账号总数</span>
          <strong>{{ overview.total }}</strong>
        </div>
        <div class="overview-chip">
          <span>可立即发布</span>
          <strong>{{ overview.immediate }}</strong>
        </div>
        <div class="overview-chip">
          <span>离线排队</span>
          <strong>{{ overview.queued }}</strong>
        </div>
        <div class="overview-chip">
          <span>需处理</span>
          <strong>{{ overview.attention }}</strong>
        </div>
      </div>
    </section>

    <section class="panel media-list-panel">
      <div class="media-list-toolbar">
        <a-input
          v-model:value="searchQuery"
          placeholder="搜索昵称、UID、平台、客户端"
          class="media-search"
          allow-clear
        >
          <template #prefix>
            <SearchOutlined style="color: #8c8c8c" />
          </template>
        </a-input>

        <a-select v-model:value="selectedHealth" style="width: 160px">
          <a-select-option value="all">全部状态</a-select-option>
          <a-select-option value="live">授权正常</a-select-option>
          <a-select-option value="captcha">待处理</a-select-option>
          <a-select-option value="risk">风险观察</a-select-option>
          <a-select-option value="expired">授权异常</a-select-option>
        </a-select>
      </div>

      <div class="media-list-header">
        <h3 class="panel-title">已绑定媒体账号</h3>
        <p class="panel-desc">只展示当前用户已经写入 `platform_accounts` 的账号，本地没有 session / partition 的账号不会出现在这里。</p>
      </div>

      <a-spin :spinning="loading">
        <a-empty
          v-if="!filteredAccounts.length"
          description="当前还没有可展示的媒体账号，请先在桌面端绑定。"
        />

        <section v-else class="media-grid">
          <article
            v-for="account in filteredAccounts"
            :key="account.id"
            class="media-card"
          >
            <div class="media-card__head">
              <div class="media-card__identity">
                <span class="media-card__avatar" :style="{ background: account.platformAccent }">
                  <img v-if="account.avatarUrl" :src="account.avatarUrl" :alt="account.displayName" referrerpolicy="no-referrer" />
                  <span v-else>{{ accountInitial(account) }}</span>
                </span>

                <div class="media-card__identity-copy">
                  <h3>{{ account.displayName }}</h3>
                  <p>{{ account.platformLabel }}</p>
                </div>
              </div>

              <div class="media-card__platform-badge" :style="{ color: account.platformAccent }">
                <img
                  v-if="account.platformLogoUrl"
                  :src="account.platformLogoUrl"
                  :alt="account.platformLabel"
                />
                <span v-else>{{ account.platformShortName }}</span>
              </div>
            </div>

            <div class="media-card__meta">
              <div class="meta-row">
                <span class="meta-label">平台 UID</span>
                <span class="meta-value">{{ account.platformUid }}</span>
              </div>
              <div class="meta-row">
                <span class="meta-label">授权状态</span>
                <a-tag :color="healthColor(account.health)">{{ healthLabel(account.health) }}</a-tag>
              </div>
              <div class="meta-row">
                <span class="meta-label">最近校验</span>
                <span class="meta-value">{{ account.verifiedAt ? formatDateTime(account.verifiedAt) : "--" }}</span>
              </div>
              <div class="meta-row">
                <span class="meta-label">客户端状态</span>
                <a-tooltip :title="clientStatusText(account)" placement="topLeft">
                  <a-tag :color="clientStatusColor(account)" class="client-status-tag">
                    {{ clientStatusText(account) }}
                  </a-tag>
                </a-tooltip>
              </div>
              <div class="meta-row">
                <span class="meta-label">最近心跳</span>
                <span class="meta-value">{{ account.clientLastSeenAt ? formatDateTime(account.clientLastSeenAt) : "--" }}</span>
              </div>
              <div class="meta-row">
                <span class="meta-label">发布状态</span>
                <a-tag :color="publishStateColor(account.publishState)">{{ publishStateLabel(account.publishState) }}</a-tag>
              </div>
            </div>

            <div v-if="account.deleteRequestedAt || account.publishHint" class="media-card__footer">
              <span v-if="account.deleteRequestedAt" class="footer-badge footer-badge--warning">
                已申请解绑
              </span>
              <span v-else-if="account.publishHint" class="footer-badge">
                {{ account.publishHint }}
              </span>
            </div>
          </article>
        </section>
      </a-spin>
    </section>
  </div>
</template>

<style scoped>
.media-view {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.media-view__top-card {
  background: #fff;
  border: 1px solid #e6edf5;
  border-radius: 12px;
  overflow: hidden;
}

.media-view__header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  padding: 24px;
}

.media-view__header-title h2 {
  margin: 0;
  font-size: 20px;
  font-weight: 600;
  color: #1a1a1a;
  line-height: 1.4;
}

.media-view__header-title p {
  margin: 6px 0 0;
  font-size: 13px;
  color: #8c8c8c;
  line-height: 1.7;
}

.media-view__header-actions {
  display: flex;
  gap: 12px;
}

.overview-strip {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

.overview-chip {
  padding: 18px 24px;
  border-top: 1px solid #eef2f7;
  border-right: 1px solid #eef2f7;
}

.overview-chip:last-child {
  border-right: none;
}

.overview-chip span {
  display: block;
  color: #8c8c8c;
  font-size: 12px;
}

.overview-chip strong {
  display: block;
  margin-top: 8px;
  color: #1a1a1a;
  font-size: 24px;
  font-weight: 700;
}

.panel {
  background: #fff;
  border-radius: 12px;
  padding: 24px;
  border: 1px solid #e6edf5;
}

.media-list-panel {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.media-list-toolbar {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: center;
}

.media-search {
  width: 320px;
}

.media-list-header {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.panel-title {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  color: #1a1a1a;
}

.panel-desc {
  margin: 0;
  color: #8c8c8c;
  font-size: 13px;
  line-height: 1.7;
}

.media-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 18px;
}

.media-card {
  border: 1px solid #e6edf5;
  border-radius: 16px;
  padding: 18px;
  background:
    radial-gradient(circle at top right, rgba(31, 92, 255, 0.06), transparent 28%),
    linear-gradient(180deg, #ffffff 0%, #fbfcff 100%);
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.media-card__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}

.media-card__identity {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

.media-card__avatar {
  width: 44px;
  height: 44px;
  border-radius: 14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 18px;
  font-weight: 700;
  overflow: hidden;
  flex-shrink: 0;
}

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

.media-card__identity-copy {
  min-width: 0;
}

.media-card__identity-copy h3 {
  margin: 0;
  color: #1a1a1a;
  font-size: 15px;
  font-weight: 700;
  line-height: 1.3;
}

.media-card__identity-copy p {
  margin: 4px 0 0;
  color: #8c8c8c;
  font-size: 12px;
}

.media-card__platform-badge {
  width: 36px;
  height: 36px;
  border-radius: 12px;
  background: #f7f9fc;
  border: 1px solid #e6edf5;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 15px;
  font-weight: 700;
  flex-shrink: 0;
  overflow: hidden;
}

.media-card__platform-badge img {
  width: 20px;
  height: 20px;
  object-fit: contain;
}

.media-card__meta {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.meta-row {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: center;
}

.meta-label {
  color: #8c8c8c;
  font-size: 12px;
  flex-shrink: 0;
}

.meta-value {
  color: #1a1a1a;
  font-size: 13px;
  font-weight: 500;
  text-align: right;
  word-break: break-all;
}

.client-status-tag {
  max-width: 160px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: middle;
}

.media-card__footer {
  padding-top: 4px;
}

.footer-badge {
  display: inline-flex;
  align-items: center;
  min-height: 28px;
  padding: 0 10px;
  border-radius: 999px;
  background: #f3f6fb;
  color: #516074;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.6;
}

.footer-badge--warning {
  background: #fff7e6;
  color: #d48806;
}

@media (max-width: 900px) {
  .overview-strip {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .overview-chip:nth-child(2) {
    border-right: none;
  }

  .overview-chip:nth-child(n + 3) {
    border-top: 1px solid #eef2f7;
  }

  .media-list-toolbar {
    flex-direction: column;
    align-items: stretch;
  }

  .media-search {
    width: 100%;
  }
}
</style>
