<script setup>
import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue";
import { apiFetch, ensureMe, userRef } from "../lib/api";
import BbModal from "../components/BbModal.vue";

const loadingUsers = ref(false);
const usersError = ref("");
const users = ref([]);

const selectedUserId = ref("");
const selectedUser = computed(() => users.value.find((u) => u.id === selectedUserId.value) || null);

const q = ref("");
const loadingBookmarks = ref(false);
const bookmarksError = ref("");
const bookmarks = ref([]);

const loadingFolders = ref(false);
const foldersError = ref("");
const folders = ref([]);

const openFolderIds = ref(new Set());

const isAdmin = computed(() => userRef.value?.role === "admin");

const confirmOpen = ref(false);
const confirmTitle = ref("请确认");
const confirmMessage = ref("");
const confirmOkText = ref("确定");
const confirmDanger = ref(false);
let confirmResolve = null;

function askConfirm(message, { title = "请确认", okText = "确定", danger = false } = {}) {
  confirmTitle.value = title;
  confirmMessage.value = message;
  confirmOkText.value = okText;
  confirmDanger.value = danger;
  confirmOpen.value = true;
  return new Promise((resolve) => {
    confirmResolve = resolve;
  });
}

function resolveConfirm(result) {
  const resolve = confirmResolve;
  confirmResolve = null;
  confirmOpen.value = false;
  if (resolve) resolve(Boolean(result));
}

function onConfirmModalUpdate(v) {
  if (!v) resolveConfirm(false);
  else confirmOpen.value = true;
}

async function loadUsers() {
  loadingUsers.value = true;
  usersError.value = "";
  try {
    users.value = await apiFetch("/admin/users");
    if (!selectedUserId.value && users.value.length) selectedUserId.value = users.value[0].id;
  } catch (e) {
    usersError.value = e.message || String(e);
  } finally {
    loadingUsers.value = false;
  }
}

async function loadFolders() {
  if (!selectedUserId.value) return;
  loadingFolders.value = true;
  foldersError.value = "";
  try {
    folders.value = await apiFetch(`/admin/users/${selectedUserId.value}/folders`);
  } catch (e) {
    foldersError.value = e.message || String(e);
  } finally {
    loadingFolders.value = false;
  }
}

async function loadBookmarks() {
  if (!selectedUserId.value) return;
  loadingBookmarks.value = true;
  bookmarksError.value = "";
  try {
    const qs = q.value.trim() ? `?q=${encodeURIComponent(q.value.trim())}` : "";
    bookmarks.value = await apiFetch(`/admin/users/${selectedUserId.value}/bookmarks${qs}`);
  } catch (e) {
    bookmarksError.value = e.message || String(e);
  } finally {
    loadingBookmarks.value = false;
  }
}

let searchTimer = 0;
watch(
  () => q.value,
  () => {
    window.clearTimeout(searchTimer);
    searchTimer = window.setTimeout(() => {
      loadBookmarks();
    }, 200);
  }
);

onBeforeUnmount(() => {
  window.clearTimeout(searchTimer);
});

function selectUser(id) {
  selectedUserId.value = id;
  q.value = "";
  folders.value = [];
  bookmarks.value = [];
  openFolderIds.value = new Set(["ROOT"]);
  loadFolders();
  loadBookmarks();
}

function openUrl(url) {
  if (!url) return;
  window.open(url, "_blank", "noopener,noreferrer");
}

function buildFolderFlat(list) {
  const byId = new Map((list || []).map((f) => [f.id, f]));
  const children = new Map();
  for (const f of list || []) {
    const key = f.parentId ?? null;
    if (!children.has(key)) children.set(key, []);
    children.get(key).push(f);
  }
  for (const arr of children.values()) {
    arr.sort((a, b) => {
      const ao = Number.isFinite(a.sortOrder) ? a.sortOrder : 0;
      const bo = Number.isFinite(b.sortOrder) ? b.sortOrder : 0;
      if (ao !== bo) return ao - bo;
      return String(a.name || "").localeCompare(String(b.name || ""));
    });
  }

  const out = [];
  const visited = new Set();
  function walk(parentId, depth) {
    const arr = children.get(parentId ?? null) || [];
    for (const f of arr) {
      if (!f?.id || visited.has(f.id)) continue;
      visited.add(f.id);
      out.push({ folder: f, depth });
      walk(f.id, depth + 1);
    }
  }
  walk(null, 0);

  for (const f of list || []) {
    if (f?.id && !visited.has(f.id) && byId.has(f.id)) {
      out.push({ folder: f, depth: 0 });
      visited.add(f.id);
    }
  }
  return out;
}

const folderFlat = computed(() => buildFolderFlat(folders.value));
const bookmarksByFolderId = computed(() => {
  const map = new Map();
  for (const b of bookmarks.value || []) {
    const key = b.folderId ?? null;
    if (!map.has(key)) map.set(key, []);
    map.get(key).push(b);
  }
  for (const arr of map.values()) {
    arr.sort((a, b) => {
      const ao = Number.isFinite(a.sortOrder) ? a.sortOrder : 0;
      const bo = Number.isFinite(b.sortOrder) ? b.sortOrder : 0;
      if (ao !== bo) return ao - bo;
      return String(b.updatedAt || "").localeCompare(String(a.updatedAt || ""));
    });
  }
  return map;
});

function folderCount(folderId) {
  return (bookmarksByFolderId.value.get(folderId ?? null) || []).length;
}

function toggleFolder(folderId) {
  const set = new Set(openFolderIds.value);
  if (set.has(folderId)) set.delete(folderId);
  else set.add(folderId);
  openFolderIds.value = set;
}

function isFolderOpen(folderId) {
  return openFolderIds.value.has(folderId);
}

async function deleteBookmark(bookmarkId) {
  if (!selectedUserId.value) return;
  if (!(await askConfirm("确定删除该书签？", { title: "删除书签", okText: "删除", danger: true }))) return;
  try {
    await apiFetch(`/admin/users/${selectedUserId.value}/bookmarks/${bookmarkId}`, { method: "DELETE" });
    await loadBookmarks();
  } catch (e) {
    bookmarksError.value = e.message || String(e);
  }
}

async function deleteFolder(folderId) {
  if (!selectedUserId.value) return;
  if (!(await askConfirm("确定删除该文件夹？子文件夹会一起删除，文件夹内书签会变成未分组。", { title: "删除文件夹", okText: "删除", danger: true }))) return;
  try {
    await apiFetch(`/admin/users/${selectedUserId.value}/folders/${folderId}`, { method: "DELETE" });
    await loadFolders();
    await loadBookmarks();
  } catch (e) {
    foldersError.value = e.message || String(e);
  }
}

async function copyToMe(bookmarkId) {
  if (!selectedUserId.value) return;
  try {
    await apiFetch(`/admin/users/${selectedUserId.value}/bookmarks/${bookmarkId}/copy-to-me`, { method: "POST" });
  } catch (e) {
    bookmarksError.value = e.message || String(e);
  }
}

onMounted(async () => {
  await ensureMe();
  if (!isAdmin.value) return;
  await loadUsers();
  if (selectedUserId.value) openFolderIds.value = new Set(["ROOT"]);
  await loadFolders();
  await loadBookmarks();
});
</script>

<template>
  <section class="bb-page">
    <div class="bb-pageHeader">
      <div>
        <h1 style="margin: 0;">管理用户</h1>
        <div class="bb-muted" style="margin-top: 4px;">仅管理员可见：查看用户列表与其书签。</div>
      </div>
    </div>

    <div v-if="!isAdmin" class="bb-empty" style="margin-top: 12px;">
      <div style="font-weight: 900;">无权限</div>
      <div class="bb-muted" style="margin-top: 6px;">当前账号不是管理员。</div>
    </div>

    <div v-else class="bb-adminGrid" style="margin-top: 12px;">
      <aside class="bb-card">
        <div class="bb-cardTitle">用户</div>
        <div class="bb-muted" style="margin-top: 4px;">点击查看该用户书签</div>

        <p v-if="usersError" class="bb-alert bb-alert--error" style="margin-top: 10px;">{{ usersError }}</p>
        <p v-else-if="loadingUsers" class="bb-muted" style="margin-top: 10px;">加载中…</p>

        <div v-else class="bb-adminUserList" style="margin-top: 10px;">
          <button
            v-for="u in users"
            :key="u.id"
            type="button"
            class="bb-adminUser"
            :class="u.id === selectedUserId ? 'is-active' : ''"
            @click="selectUser(u.id)"
          >
            <div class="email">{{ u.email }}</div>
            <div class="meta">{{ u.role === 'admin' ? '管理员' : '用户' }}</div>
          </button>
        </div>
      </aside>

      <section class="bb-card">
        <div class="bb-row" style="justify-content: space-between; align-items: flex-end;">
          <div>
            <div class="bb-cardTitle">书签</div>
            <div class="bb-muted" style="margin-top: 4px;">
              <span v-if="selectedUser">当前：{{ selectedUser.email }}</span>
              <span v-else>请选择一个用户</span>
            </div>
          </div>

          <div class="bb-row" style="gap: 8px;">
            <div class="bb-searchWrap" style="min-width: 260px;">
              <input v-model="q" class="bb-input bb-input--sm bb-input--withClear" placeholder="搜索标题/链接" />
              <button v-if="q.trim()" class="bb-searchClear" type="button" aria-label="清空搜索" @click="q = ''">×</button>
            </div>
          </div>
        </div>

        <p v-if="bookmarksError" class="bb-alert bb-alert--error" style="margin-top: 12px;">{{ bookmarksError }}</p>
        <p v-else-if="loadingBookmarks" class="bb-muted" style="margin-top: 12px;">加载中…</p>

        <p v-if="foldersError" class="bb-alert bb-alert--error" style="margin-top: 12px;">{{ foldersError }}</p>

        <div v-else-if="(!folders.length && !bookmarks.length)" class="bb-empty" style="margin-top: 12px;">
          <div style="font-weight: 800;">暂无数据</div>
          <div class="bb-muted" style="margin-top: 6px;">该用户还没有书签或文件夹。</div>
        </div>

        <div v-else class="bb-adminTree" style="margin-top: 12px;">
          <!-- Root group -->
          <div class="bb-adminFolder" :class="isFolderOpen('ROOT') ? 'is-open' : ''">
            <button type="button" class="bb-adminFolderHeader" @click="toggleFolder('ROOT')">
              <span class="name">未分组</span>
              <span class="meta">{{ folderCount(null) }} 条</span>
            </button>
            <div v-if="isFolderOpen('ROOT')" class="bb-adminFolderBody">
              <ul class="bb-adminBookmarks">
                <li
                  v-for="b in (bookmarksByFolderId.get(null) || [])"
                  :key="b.id"
                  class="bb-card bb-card--interactive bb-clickCard"
                  role="link"
                  tabindex="0"
                  @click="openUrl(b.url)"
                  @keydown.enter.prevent="openUrl(b.url)"
                  @keydown.space.prevent="openUrl(b.url)"
                >
                  <div class="bb-bookmarkTitle" style="font-weight: 900; color: var(--bb-text);">{{ b.title }}</div>
                  <div class="bb-muted" style="overflow-wrap: anywhere; margin-top: 6px;">{{ b.url }}</div>
                  <div class="bb-adminActions" style="margin-top: 10px;">
                    <button class="bb-btn bb-btn--secondary" type="button" @click.stop="copyToMe(b.id)">复制到我</button>
                    <button class="bb-btn bb-btn--danger" type="button" @click.stop="deleteBookmark(b.id)">删除</button>
                  </div>
                </li>
              </ul>
            </div>
          </div>

          <!-- Folder tree (flat with indent) -->
          <div
            v-for="x in folderFlat"
            :key="x.folder.id"
            class="bb-adminFolder"
            :class="isFolderOpen(x.folder.id) ? 'is-open' : ''"
            :style="{ paddingLeft: `${x.depth * 14}px` }"
          >
            <div class="bb-adminFolderHeaderRow">
              <button type="button" class="bb-adminFolderHeader" @click="toggleFolder(x.folder.id)">
                <span class="name">{{ x.folder.name }}</span>
                <span class="meta">{{ folderCount(x.folder.id) }} 条</span>
              </button>
              <button class="bb-btn bb-btn--danger bb-adminFolderDel" type="button" @click.stop="deleteFolder(x.folder.id)">删除文件夹</button>
            </div>

            <div v-if="isFolderOpen(x.folder.id)" class="bb-adminFolderBody">
              <ul class="bb-adminBookmarks">
                <li
                  v-for="b in (bookmarksByFolderId.get(x.folder.id) || [])"
                  :key="b.id"
                  class="bb-card bb-card--interactive bb-clickCard"
                  role="link"
                  tabindex="0"
                  @click="openUrl(b.url)"
                  @keydown.enter.prevent="openUrl(b.url)"
                  @keydown.space.prevent="openUrl(b.url)"
                >
                  <div class="bb-bookmarkTitle" style="font-weight: 900; color: var(--bb-text);">{{ b.title }}</div>
                  <div class="bb-muted" style="overflow-wrap: anywhere; margin-top: 6px;">{{ b.url }}</div>
                  <div class="bb-adminActions" style="margin-top: 10px;">
                    <button class="bb-btn bb-btn--secondary" type="button" @click.stop="copyToMe(b.id)">复制到我</button>
                    <button class="bb-btn bb-btn--danger" type="button" @click.stop="deleteBookmark(b.id)">删除</button>
                  </div>
                </li>
              </ul>
            </div>
          </div>
        </div>
      </section>
    </div>

    <BbModal :model-value="confirmOpen" :title="confirmTitle" max-width="520px" @update:model-value="onConfirmModalUpdate">
      <div class="bb-muted" style="white-space: pre-wrap; line-height: 1.6;">{{ confirmMessage }}</div>
      <div class="bb-row" style="justify-content: flex-end; gap: 10px; margin-top: 14px;">
        <button class="bb-btn bb-btn--secondary" type="button" @click="resolveConfirm(false)">取消</button>
        <button class="bb-btn" :class="confirmDanger ? 'bb-btn--danger' : ''" type="button" @click="resolveConfirm(true)">{{ confirmOkText }}</button>
      </div>
    </BbModal>
  </section>
</template>

<style scoped>
.bb-adminGrid { display: grid; grid-template-columns: 1fr; gap: 12px; }
@media (min-width: 960px) { .bb-adminGrid { grid-template-columns: 1.1fr 2fr; } }

.bb-adminUserList { display: grid; gap: 8px; }
.bb-adminUser {
  width: 100%;
  text-align: left;
  padding: 10px 12px;
  border-radius: 16px;
  border: 1px solid rgba(255,255,255,0.45);
  background: rgba(255,255,255,0.35);
  cursor: pointer;
}
.bb-adminUser:hover { background: rgba(255,255,255,0.6); }
.bb-adminUser.is-active { background: rgba(13, 148, 136, 0.12); border-color: rgba(13, 148, 136, 0.22); }
.bb-adminUser .email { font-weight: 800; color: var(--bb-text); }
.bb-adminUser .meta { font-size: 12px; color: rgba(19, 78, 74, 0.72); margin-top: 2px; }

.bb-adminBookmarks { list-style: none; padding: 0; margin: 12px 0 0; display: grid; grid-template-columns: 1fr; gap: 10px; }
@media (min-width: 768px) { .bb-adminBookmarks { grid-template-columns: 1fr 1fr; } }

.bb-clickCard { cursor: pointer; }
.title { font-weight: 900; color: var(--bb-text); }

.bb-adminFolder { margin-top: 10px; }
.bb-adminFolderHeaderRow { display: flex; gap: 10px; align-items: center; }
.bb-adminFolderHeader {
  flex: 1;
  width: 100%;
  text-align: left;
  padding: 10px 12px;
  border-radius: 16px;
  border: 1px solid rgba(255,255,255,0.45);
  background: rgba(255,255,255,0.35);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.bb-adminFolderHeader:hover { background: rgba(255,255,255,0.6); }
.bb-adminFolderHeader .name { font-weight: 900; color: var(--bb-text); }
.bb-adminFolderHeader .meta { font-size: 12px; color: rgba(19, 78, 74, 0.72); }
.bb-adminFolderBody { margin-top: 10px; }
.bb-adminFolderDel { white-space: nowrap; }
.bb-adminActions { display: flex; gap: 8px; flex-wrap: wrap; }
</style>
