<template>
  <view class="page">
    <view v-if="useRemote" class="api-bar">
      <text class="api-bar-txt">已连接后端 API</text>
      <view v-if="!adminToken" class="login-row">
        <input
          v-model="loginUser"
          class="login-inp"
          placeholder="管理员账号"
        />
        <input
          v-model="loginPass"
          class="login-inp"
          password
          placeholder="密码"
        />
        <view class="login-go" @click="doLogin"><text>登录</text></view>
      </view>
      <view v-else class="login-row">
        <text class="login-ok">已登录管理端</text>
        <view class="login-out" @click="doLogout"><text>退出</text></view>
        <view class="login-out" @click="loadAll"><text>刷新</text></view>
      </view>
    </view>
    <view class="stats">
      <view class="stat">
        <text class="stat-num stat-blue">{{ pendingPhotos.length }}</text>
        <text class="stat-label">待审核</text>
      </view>
      <view class="stat">
        <text class="stat-num stat-green">{{ approvedPhotos.length }}</text>
        <text class="stat-label">已通过</text>
      </view>
    </view>

    <view class="tabs">
      <view
        :class="['tab', activeTab === 'pending' ? 'tab-on' : '']"
        @click="activeTab = 'pending'"
      >
        <text>待审核作品</text>
        <text v-if="pendingPhotos.length" class="badge">{{ pendingPhotos.length }}</text>
      </view>
      <view
        :class="['tab', activeTab === 'approved' ? 'tab-on' : '']"
        @click="activeTab = 'approved'"
      >
        <text>已通过作品</text>
      </view>
    </view>

    <view v-if="activeTab === 'pending'" class="panel">
      <view v-if="pendingPhotos.length === 0" class="empty">
        <text class="empty-ico">✓</text>
        <text class="empty-txt">暂无待审核作品</text>
      </view>
      <view v-for="photo in pendingPhotos" :key="photo.id" class="card">
        <image class="card-cover" :src="photo.imageUrl" mode="aspectFill" />
        <view class="card-pad">
          <text class="card-title">{{ photo.title }}</text>
          <text class="card-meta">@{{ photo.author }} · {{ photo.uploadDate }}</text>
          <view class="row-btns">
            <view class="btn ok" @click="handleApprove(photo.id)">
              <text>通过</text>
            </view>
            <view class="btn no" @click="handleReject(photo.id)">
              <text>拒绝</text>
            </view>
          </view>
        </view>
      </view>
    </view>

    <view v-else class="panel">
      <view
        v-for="(photo, index) in approvedPhotos"
        :key="photo.id"
        class="ap-card"
      >
        <image class="ap-img" :src="photo.imageUrl" mode="aspectFill" />
        <view class="ap-body">
          <view class="ap-top">
            <view class="ap-titles">
              <text class="ap-title">{{ photo.title }}</text>
              <text class="ap-meta">@{{ photo.author }}</text>
            </view>
          </view>
          <view class="ap-actions">
            <view
              :class="['icon-btn', index === 0 ? 'disabled' : '']"
              @click="handleMoveUp(photo.id)"
            >
              <text>↑</text>
            </view>
            <view
              :class="[
                'icon-btn',
                index === approvedPhotos.length - 1 ? 'disabled' : '',
              ]"
              @click="handleMoveDown(photo.id)"
            >
              <text>↓</text>
            </view>
          </view>
        </view>
      </view>
    </view>
  </view>
</template>

<script setup lang="ts">
import { computed, onMounted, ref } from "vue";
import { localGalleryByIndex } from "@/utils/localGalleryImages";
import { staticAsset } from "@/utils/staticAsset";
import { apiEnabled } from "@/config/api";
import { resolveMediaUrl } from "@/utils/mediaUrl";
import {
  adminGet,
  adminLogin,
  adminPost,
  clearAdminToken,
  getAdminToken,
} from "@/utils/api/adminHttp";

interface PendingPhoto {
  id: number;
  imageUrl: string;
  title: string;
  author: string;
  uploadDate: string;
}

interface ApprovedPhoto extends PendingPhoto {
  order: number;
}

const mockPending: PendingPhoto[] = [
  {
    id: 1,
    imageUrl: localGalleryByIndex(1),
    title: "五色海晨曦",
    author: "云游四方",
    uploadDate: "2026-03-26",
  },
  {
    id: 2,
    imageUrl: staticAsset("photo-sangdui-caoyuan.png"),
    title: "草原牧歌",
    author: "摄影师小李",
    uploadDate: "2026-03-26",
  },
  {
    id: 3,
    imageUrl: localGalleryByIndex(3),
    title: "经幡随风",
    author: "藏地风情",
    uploadDate: "2026-03-25",
  },
];

const mockApproved: ApprovedPhoto[] = [
  {
    id: 101,
    imageUrl: staticAsset("photo-xiannairi-xuefeng.png"),
    title: "仙乃日雪峰",
    author: "山行者",
    uploadDate: "2026-03-20",
    order: 1,
  },
  {
    id: 102,
    imageUrl: localGalleryByIndex(5),
    title: "秋色森林",
    author: "四季光影",
    uploadDate: "2026-03-18",
    order: 2,
  },
];

const pendingPhotos = ref<PendingPhoto[]>([...mockPending]);
const approvedPhotos = ref<ApprovedPhoto[]>([...mockApproved]);
const activeTab = ref<"pending" | "approved">("pending");

const useRemote = computed(() => apiEnabled());
const adminToken = ref("");
const loginUser = ref("admin");
const loginPass = ref("");

onMounted(() => {
  adminToken.value = getAdminToken();
  if (useRemote.value && adminToken.value) {
    void loadAll();
  }
});

async function doLogin() {
  try {
    await adminLogin(loginUser.value.trim(), loginPass.value);
    adminToken.value = getAdminToken();
    uni.showToast({ title: "登录成功", icon: "success" });
    await loadAll();
  } catch (e) {
    const msg =
      e && typeof e === "object" && "msg" in e
        ? String((e as { msg: string }).msg)
        : "登录失败";
    uni.showToast({ title: msg, icon: "none" });
  }
}

function doLogout() {
  clearAdminToken();
  adminToken.value = "";
  pendingPhotos.value = [...mockPending];
  approvedPhotos.value = [...mockApproved];
}

async function loadAll() {
  if (!useRemote.value || !getAdminToken()) {
    return;
  }
  try {
    const [st, pen, app] = await Promise.all([
      adminGet<{ pending: number; approved: number }>(
        "/admin/v1/dashboard/stats"
      ),
      adminGet<{ list: PendingPhoto[] }>("/admin/v1/works/pending"),
      adminGet<{ list: ApprovedPhoto[] }>("/admin/v1/works/approved"),
    ]);
    void st;
    pendingPhotos.value = pen.data.list.map((p) => ({
      id: p.id,
      imageUrl: resolveMediaUrl(p.imageUrl),
      title: p.title,
      author: p.author,
      uploadDate: p.uploadDate,
    }));
    approvedPhotos.value = app.data.list.map((p) => ({
      id: p.id,
      imageUrl: resolveMediaUrl(p.imageUrl),
      title: p.title,
      author: p.author,
      uploadDate: p.uploadDate,
      order: p.order,
    }));
  } catch {
    uni.showToast({ title: "加载失败", icon: "none" });
  }
}

async function handleApprove(id: number) {
  if (useRemote.value && adminToken.value) {
    try {
      await adminPost(`/admin/v1/works/${id}/approve`, {});
      await loadAll();
      uni.showToast({ title: "作品已通过审核", icon: "success" });
    } catch {
      uni.showToast({ title: "操作失败", icon: "none" });
    }
    return;
  }
  pendingPhotos.value = pendingPhotos.value.filter((p) => p.id !== id);
  uni.showToast({ title: "作品已通过审核", icon: "success" });
}

async function handleReject(id: number) {
  if (useRemote.value && adminToken.value) {
    try {
      await adminPost(`/admin/v1/works/${id}/reject`, {});
      await loadAll();
      uni.showToast({ title: "作品已拒绝", icon: "none" });
    } catch {
      uni.showToast({ title: "操作失败", icon: "none" });
    }
    return;
  }
  pendingPhotos.value = pendingPhotos.value.filter((p) => p.id !== id);
  uni.showToast({ title: "作品已拒绝", icon: "none" });
}

async function handleMoveUp(id: number) {
  const i = approvedPhotos.value.findIndex((p) => p.id === id);
  if (i <= 0) return;
  const arr = [...approvedPhotos.value];
  [arr[i - 1], arr[i]] = [arr[i], arr[i - 1]];
  approvedPhotos.value = arr;
  if (useRemote.value && adminToken.value) {
    try {
      await adminPost("/admin/v1/works/sort", {
        ids: approvedPhotos.value.map((p) => p.id),
      });
    } catch {
      uni.showToast({ title: "排序保存失败", icon: "none" });
    }
  }
}

async function handleMoveDown(id: number) {
  const i = approvedPhotos.value.findIndex((p) => p.id === id);
  if (i < 0 || i >= approvedPhotos.value.length - 1) return;
  const arr = [...approvedPhotos.value];
  [arr[i + 1], arr[i]] = [arr[i], arr[i + 1]];
  approvedPhotos.value = arr;
  if (useRemote.value && adminToken.value) {
    try {
      await adminPost("/admin/v1/works/sort", {
        ids: approvedPhotos.value.map((p) => p.id),
      });
    } catch {
      uni.showToast({ title: "排序保存失败", icon: "none" });
    }
  }
}
</script>

<style scoped>
.page {
  min-height: 100vh;
  padding: 32rpx;
  padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  background: #f9fafb;
}

.api-bar {
  margin-bottom: 24rpx;
  padding: 24rpx;
  border-radius: 24rpx;
  background: #fff;
  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
}

.api-bar-txt {
  display: block;
  margin-bottom: 16rpx;
  font-size: 24rpx;
  color: #6b7280;
}

.login-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16rpx;
}

.login-inp {
  box-sizing: border-box;
  flex: 1;
  min-width: 200rpx;
  height: 72rpx;
  padding: 0 20rpx;
  font-size: 26rpx;
  border: 1rpx solid #e5e7eb;
  border-radius: 16rpx;
}

.login-go {
  padding: 16rpx 32rpx;
  font-size: 26rpx;
  color: #fff;
  border-radius: 16rpx;
  background: #4a90e2;
}

.login-ok {
  font-size: 26rpx;
  color: #15803d;
}

.login-out {
  padding: 12rpx 24rpx;
  font-size: 24rpx;
  color: #4b5563;
  border-radius: 12rpx;
  background: #f3f4f6;
}

.stats {
  display: grid;
  margin-bottom: 32rpx;
  gap: 24rpx;
  grid-template-columns: repeat(2, 1fr);
}

.stat {
  padding: 32rpx 16rpx;
  text-align: center;
  background: #fff;
  border-radius: 24rpx;
  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
}

.stat-num {
  display: block;
  margin-bottom: 8rpx;
  font-size: 44rpx;
  font-weight: 600;
}

.stat-blue {
  color: #4a90e2;
}

.stat-green {
  color: #7fb069;
}

.stat-label {
  font-size: 22rpx;
  color: #4b5563;
}

.tabs {
  display: grid;
  margin-bottom: 32rpx;
  padding: 8rpx;
  border-radius: 24rpx;
  background: #fff;
  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
  grid-template-columns: 1fr 1fr;
}

.tab {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20rpx;
  font-size: 26rpx;
  color: #6b7280;
  border-radius: 20rpx;
  gap: 12rpx;
}

.tab-on {
  color: #111827;
  background: #f3f4f6;
  font-weight: 500;
}

.badge {
  min-width: 36rpx;
  padding: 4rpx 12rpx;
  font-size: 20rpx;
  color: #fff;
  text-align: center;
  background: #ef4444;
  border-radius: 999rpx;
}

.panel {
  padding-bottom: 48rpx;
}

.empty {
  padding: 120rpx 0;
  text-align: center;
}

.empty-ico {
  display: block;
  margin-bottom: 24rpx;
  font-size: 72rpx;
  color: #d1d5db;
}

.empty-txt {
  font-size: 26rpx;
  color: #9ca3af;
}

.card {
  overflow: hidden;
  margin-bottom: 32rpx;
  border-radius: 24rpx;
  background: #fff;
  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
}

.card-cover {
  width: 100%;
  height: 360rpx;
  background: #f3f4f6;
}

.card-pad {
  padding: 32rpx;
}

.card-title {
  display: block;
  margin-bottom: 12rpx;
  font-size: 32rpx;
  color: #111827;
}

.card-meta {
  margin-bottom: 24rpx;
  font-size: 22rpx;
  color: #6b7280;
}

.row-btns {
  display: flex;
  gap: 24rpx;
}

.btn {
  display: flex;
  flex: 1;
  align-items: center;
  justify-content: center;
  height: 80rpx;
  font-size: 28rpx;
  border-radius: 20rpx;
}

.btn.ok {
  color: #fff;
  background: #7fb069;
}

.btn.no {
  box-sizing: border-box;
  color: #dc2626;
  background: #fff;
  border: 1rpx solid #fca5a5;
}

.ap-card {
  display: flex;
  padding: 32rpx;
  margin-bottom: 32rpx;
  border-radius: 24rpx;
  background: #fff;
  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
  gap: 32rpx;
}

.ap-img {
  width: 192rpx;
  height: 192rpx;
  flex-shrink: 0;
  border-radius: 20rpx;
  background: #f3f4f6;
}

.ap-body {
  flex: 1;
  min-width: 0;
}

.ap-top {
  margin-bottom: 20rpx;
}

.ap-titles {
  flex: 1;
  min-width: 0;
}

.ap-title {
  display: block;
  margin-bottom: 8rpx;
  overflow: hidden;
  font-size: 28rpx;
  color: #111827;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ap-meta {
  font-size: 22rpx;
  color: #6b7280;
}

.ap-actions {
  display: flex;
  align-items: center;
  gap: 12rpx;
}

.icon-btn {
  display: flex;
  width: 56rpx;
  height: 56rpx;
  align-items: center;
  justify-content: center;
  border-radius: 12rpx;
  background: #f3f4f6;
  font-size: 28rpx;
}

.icon-btn.disabled {
  opacity: 0.35;
}
</style>
