<template>
  <view class="page">
    <view :style="{ paddingTop: statusBarHeight + 'px' }" class="nav">
      <view class="nav-inner">
        <view class="nav-placeholder" />
        <text class="nav-title">{{ isResubmitMode ? "修改作品" : "上传作品" }}</text>
        <view class="nav-placeholder" />
      </view>
    </view>

    <view class="audit-banner" :class="{ 'audit-banner-warn': isResubmitMode }">
      <text class="audit-banner-txt">{{
        isResubmitMode
          ? "该作品未通过审核，修改后重新提交将再次进入审核"
          : "发布后将进入审核流程，通过后即可在作品墙展示"
      }}</text>
    </view>

    <view class="body">
      <view class="section">
        <view class="label label-with-star">
          <text class="label-main">作品图片（最多3张，16:9 横幅）</text>
          <text class="label-star">*</text>
        </view>
        <text class="hint-169">仅支持横向照片（宽大于高），选图后自动居中裁为 16:9 横幅</text>
        <view class="grid-3">
          <view v-for="(img, index) in uploadedImages" :key="index" class="cell">
            <image class="cell-img" :src="img" mode="aspectFill" />
            <view class="cell-x" @click="removeImage(index)">
              <text class="x-txt">×</text>
            </view>
          </view>
          <view
            v-if="uploadedImages.length < MAX_WORK_IMAGES"
            class="cell add"
            @click="pickImages"
          >
            <view class="add-inner">
              <image
                class="add-ico-img"
                :src="addIcon"
                mode="aspectFit"
              />
              <text class="add-txt">添加作品</text>
            </view>
          </view>
        </view>
      </view>

      <!-- #ifdef MP-WEIXIN -->
      <canvas
        canvas-id="crop16"
        id="crop16"
        class="crop-hidden"
        :style="{ width: '320px', height: '180px' }"
      />
      <!-- #endif -->

      <view class="section">
        <view class="label label-with-star">
          <text class="label-main">作品标题</text>
          <text class="label-star">*</text>
        </view>
        <input
          v-model="formData.title"
          class="input"
          maxlength="10"
          placeholder="给你的作品起个名字（限10字）"
        />
      </view>

      <view class="section">
        <view class="label label-with-star">
          <text class="label-main">作品描述</text>
          <text class="label-star">*</text>
        </view>
        <view class="textarea-wrap">
          <textarea
            v-model="formData.description"
            class="textarea"
            maxlength="100"
            placeholder="分享你创作这幅作品时的故事...（限100字）"
          />
          <text class="textarea-count">{{ formData.description.length }}/100</text>
        </view>
      </view>

      <view class="section">
        <view class="label label-with-star">
          <text class="label-main">作品类别</text>
          <text class="label-star">*</text>
        </view>
        <view class="cats">
          <view
            v-for="cat in categoryOptions"
            :key="cat.value"
            :class="[
              'cat',
              formData.categories.includes(cat.value) ? 'cat-on' : '',
            ]"
            @click="toggleCategory(cat.value)"
          >
            <text>{{ cat.label }}</text>
          </view>
        </view>
      </view>

      <view class="section">
        <text class="label label-nowrap">拍摄日期（选填）</text>
        <picker
          mode="date"
          :value="formData.shootDate || todayStr"
          start="1980-01-01"
          :end="todayStr"
          @change="onShootDateChange"
        >
          <view class="date-picker-row">
            <text
              :class="['date-picker-txt', formData.shootDate ? '' : 'date-picker-ph']"
            >
              {{
                formData.shootDate
                  ? formatShootDateDisplay(formData.shootDate)
                  : "点击选择拍摄日期"
              }}
            </text>
            <text class="date-picker-arrow">›</text>
          </view>
        </picker>
      </view>
    </view>

    <view class="submit-dock">
      <view
        :class="['submit', !canSubmit ? 'submit-off' : '']"
        @click="handleSubmit"
      >
        <text>{{ isResubmitMode ? "重新提交审核" : "发布作品" }}</text>
      </view>
    </view>

    <ImageTabBar current="upload" />
  </view>
</template>

<script setup lang="ts">
import { onLoad, onShow } from "@dcloudio/uni-app";
import { computed, getCurrentInstance, onMounted, ref } from "vue";
import { cropImageTo16x9 } from "@/utils/cropImage16x9";

function pad2(n: number) {
  return n < 10 ? `0${n}` : `${n}`;
}

function ymdNow() {
  const d = new Date();
  return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
}
import ImageTabBar from "@/components/ImageTabBar.vue";
import { useHideNativeTabBar } from "@/composables/useHideNativeTabBar";
import { staticAsset } from "@/utils/staticAsset";
import {
  get,
  getMpToken,
  isMpSessionExpiredError,
  post,
  uploadImage,
} from "@/utils/api/http";
import { ensureMpSession, getMpLoginChannel } from "@/utils/api/mpSession";
import { reLaunchLoginIfNoBoundPhone } from "@/utils/guestTabGuard";
import { consumeUploadFormClearFlag } from "@/utils/uploadTabClear";
import { resolveMediaUrl } from "@/utils/mediaUrl";
import { consumeUploadResubmitWorkId } from "@/utils/uploadResubmit";

const MAX_WORK_IMAGES = 3;

const statusBarHeight = ref(20);
const addIcon = staticAsset("img.png");
const uploadedImages = ref<string[]>([]);
const formData = ref({
  title: "",
  description: "",
  shootDate: "",
  categories: [] as string[],
});

const todayStr = ref(ymdNow());
/** >0 表示从「已拒绝」进入修改并重新提交 */
const editWorkId = ref(0);

const isResubmitMode = computed(() => editWorkId.value > 0);
const apiOn = computed(() => {
  const rel = String(import.meta.env.VITE_API_RELATIVE || "").trim();
  if (rel === "1" || rel === "true") {
    return true;
  }
  const base = String(import.meta.env.VITE_API_BASE_URL || "").trim();
  return base.length > 0;
});

function resetUploadForm() {
  editWorkId.value = 0;
  uploadedImages.value = [];
  formData.value = {
    title: "",
    description: "",
    shootDate: "",
    categories: [],
  };
  todayStr.value = ymdNow();
}

function formatShootDateDisplay(ymd: string) {
  const [y, m, d] = ymd.split("-");
  if (!y || !m || !d) return ymd;
  return `${y}年${Number(m)}月${Number(d)}日`;
}

function onShootDateChange(e: { detail: { value: string } }) {
  formData.value.shootDate = e.detail.value;
}

const categoryOptions = [
  { value: "landscape", label: "风景" },
  { value: "humanity", label: "人文" },
  { value: "ecology", label: "生态" },
  { value: "other", label: "其他" },
];

const canSubmit = computed(
  () =>
    !!formData.value.title.trim() &&
    !!formData.value.description.trim() &&
    formData.value.categories.length > 0 &&
    uploadedImages.value.length > 0
);

function toggleCategory(value: string) {
  const cur = formData.value.categories;
  const i = cur.indexOf(value);
  if (i >= 0) {
    formData.value.categories = cur.filter((v) => v !== value);
  } else {
    formData.value.categories = [...cur, value];
  }
}

useHideNativeTabBar();

onLoad((opts) => {
  const raw = (opts as Record<string, string | undefined> | undefined)?.id;
  const n =
    raw != null && String(raw).trim() !== "" ? Number(raw) : Number.NaN;
  if (apiOn.value && Number.isInteger(n) && n > 0) {
    void loadWorkForEdit(n);
  }
});

onShow(() => {
  // #ifdef MP-WEIXIN
  if (apiOn.value && (!getMpToken() || getMpLoginChannel() !== "weixin")) {
    uni.reLaunch({ url: "/pages/login/login?tab=upload" });
    return;
  }
  // #endif
  // #ifndef MP-WEIXIN
  void (async () => {
    if (apiOn.value && !getMpToken()) {
      try {
        await ensureMpSession();
      } catch {
        /* ignore */
      }
    }
  })();
  // #endif
  if (reLaunchLoginIfNoBoundPhone()) {
    return;
  }
  const rid = consumeUploadResubmitWorkId();
  if (apiOn.value && rid > 0) {
    void loadWorkForEdit(rid);
    return;
  }
  if (editWorkId.value <= 0 && consumeUploadFormClearFlag()) {
    resetUploadForm();
  }
});

onMounted(() => {
  statusBarHeight.value = uni.getSystemInfoSync().statusBarHeight || 20;
});

async function pickImages() {
  const remain = MAX_WORK_IMAGES - uploadedImages.value.length;
  uni.chooseImage({
    count: remain,
    sizeType: ["compressed"],
    sourceType: ["album", "camera"],
    success: async (res) => {
      const inst = getCurrentInstance()?.proxy ?? null;
      const next: string[] = [];
      for (const p of res.tempFilePaths) {
        try {
          next.push(await cropImageTo16x9(p, inst));
        } catch (e) {
          const raw =
            e && typeof e === "object" && "errMsg" in e
              ? String((e as { errMsg?: string }).errMsg ?? "")
              : e instanceof Error
                ? e.message
                : "图片处理失败";
          const m = raw.includes("横向照片") ? raw : raw || "图片处理失败";
          uni.showToast({
            title: m.length > 36 ? `${m.slice(0, 36)}…` : m,
            icon: "none",
          });
        }
      }
      uploadedImages.value = uploadedImages.value
        .concat(next)
        .slice(0, MAX_WORK_IMAGES);
    },
  });
}

function removeImage(index: number) {
  uploadedImages.value = uploadedImages.value.filter((_, i) => i !== index);
}

function extractServerImagePath(url: string): string {
  const t = url.trim();
  if (t.startsWith("/uploads/")) {
    return t;
  }
  const i = t.indexOf("/uploads/");
  if (i >= 0) {
    return t.slice(i);
  }
  return "";
}

async function imageUrlsForSubmit(): Promise<string[]> {
  const out: string[] = [];
  for (const p of uploadedImages.value) {
    const rel = extractServerImagePath(p);
    if (rel) {
      out.push(rel);
    } else {
      out.push(await uploadImage(p));
    }
  }
  return out;
}

async function loadWorkForEdit(id: number) {
  if (!apiOn.value) {
    return;
  }
  try {
    uni.showLoading({ title: "加载中" });
    const res = await get<Record<string, unknown>>(`/api/v1/works/${id}`);
    uni.hideLoading();
    const d = res.data;
    const status = String(d.status ?? "")
      .toLowerCase()
      .trim();
    if (status !== "rejected") {
      uni.showToast({ title: "仅未通过的作品可修改", icon: "none" });
      return;
    }
    editWorkId.value = id;
    formData.value.title = String(d.title ?? "").slice(0, 10);
    formData.value.description = String(d.description ?? "").slice(0, 100);
    const sd = String(d.shootDate ?? d.shoot_date ?? "").trim();
    formData.value.shootDate = /^\d{4}-\d{2}-\d{2}$/.test(sd) ? sd : "";
    const catsRaw = d.categories;
    const cats = Array.isArray(catsRaw)
      ? catsRaw.filter((x): x is string => typeof x === "string")
      : [];
    formData.value.categories = cats.filter((c) =>
      categoryOptions.some((o) => o.value === c)
    );
    const imgsRaw = d.images;
    const imgs = Array.isArray(imgsRaw)
      ? imgsRaw.map((x) => String(x ?? "").trim()).filter(Boolean)
      : [];
    const cover = String(d.imageUrl ?? d.image_url ?? "").trim();
    const urls = imgs.length ? imgs : cover ? [cover] : [];
    uploadedImages.value = urls.map((u) => resolveMediaUrl(u));
  } catch (e) {
    uni.hideLoading();
    if (isMpSessionExpiredError(e)) {
      return;
    }
    const msg =
      e && typeof e === "object" && "msg" in e
        ? String((e as { msg: string }).msg)
        : "加载失败";
    uni.showToast({ title: msg.length > 20 ? msg.slice(0, 20) + "…" : msg, icon: "none" });
  }
}

async function handleSubmit() {
  if (!canSubmit.value) return;
  if (apiOn.value) {
    try {
      uni.showLoading({ title: "上传中" });
      const urls = await imageUrlsForSubmit();
      const body = {
        title: formData.value.title.trim(),
        description: formData.value.description.trim(),
        shoot_date: formData.value.shootDate || "",
        categories: formData.value.categories,
        image_urls: urls,
      };
      const wid = editWorkId.value;
      if (wid > 0) {
        await post(`/api/v1/works/${wid}/resubmit`, body);
      } else {
        await post("/api/v1/works", body);
      }
      uni.hideLoading();
      resetUploadForm();
      uni.showToast({
        title: wid > 0 ? "已重新提交，请等待审核" : "作品已发布，等待审核",
        icon: "success",
      });
      setTimeout(() => {
        uni.switchTab({ url: "/pages/user/user" });
      }, 800);
    } catch (e) {
      uni.hideLoading();
      if (isMpSessionExpiredError(e)) {
        return;
      }
      const msg =
        e && typeof e === "object" && "msg" in e
          ? String((e as { msg: string }).msg)
          : "提交失败";
      uni.showToast({ title: msg, icon: "none" });
    }
    return;
  }
  resetUploadForm();
  uni.showToast({ title: "作品已发布，等待审核", icon: "success" });
  setTimeout(() => {
    uni.switchTab({ url: "/pages/user/user" });
  }, 800);
}
</script>

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

.nav {
  position: sticky;
  top: 0;
  z-index: 40;
  background: #fff;
  border-bottom: 1rpx solid #e5e7eb;
}

.nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 88rpx;
}

.nav-title {
  font-size: 30rpx;
  color: #111827;
}

.nav-placeholder {
  width: 72rpx;
}

.body {
  max-width: 750rpx;
  padding: 48rpx 32rpx;
  margin: 0 auto;
}

.section {
  margin-bottom: 48rpx;
}

.label {
  display: block;
  margin-bottom: 24rpx;
  font-size: 28rpx;
  color: #374151;
}

.label-nowrap {
  white-space: nowrap;
}

.label-with-star {
  display: flex;
  align-items: center;
  gap: 6rpx;
}

.label-star {
  color: #ef4444;
  font-size: 28rpx;
  line-height: 1;
}

.hint-169 {
  display: block;
  margin: -12rpx 0 20rpx;
  font-size: 24rpx;
  line-height: 1.45;
  color: #64748b;
}

.crop-hidden {
  position: fixed;
  top: -2000px;
  left: 0;
  overflow: hidden;
}

.grid-3 {
  display: grid;
  gap: 24rpx;
  grid-template-columns: repeat(3, 1fr);
}

.cell {
  position: relative;
  overflow: hidden;
  width: 100%;
  height: 0;
  padding-bottom: 100%;
  border-radius: 24rpx;
  background: #f3f4f6;
}

.cell-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.cell-x {
  position: absolute;
  top: 8rpx;
  right: 8rpx;
  display: flex;
  width: 48rpx;
  height: 48rpx;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.45);
}

.x-txt {
  font-size: 32rpx;
  color: #fff;
}

.add {
  border: 2rpx dashed #d1d5db;
  background: transparent;
}

.add-inner {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8rpx;
}

.add-ico-img {
  width: 56rpx;
  height: 56rpx;
  flex-shrink: 0;
}

.add-txt {
  font-size: 22rpx;
  color: #6b7280;
}

.input {
  box-sizing: border-box;
  width: 100%;
  height: 88rpx;
  padding: 0 28rpx;
  font-size: 28rpx;
  border-radius: 20rpx;
  background: #fff;
}

.textarea-wrap {
  position: relative;
  width: 100%;
}

.textarea {
  box-sizing: border-box;
  width: 100%;
  min-height: 240rpx;
  padding: 24rpx 28rpx 52rpx;
  font-size: 28rpx;
  border-radius: 20rpx;
  background: #fff;
}

.textarea-count {
  position: absolute;
  right: 24rpx;
  bottom: 16rpx;
  font-size: 22rpx;
  line-height: 1;
  color: #9ca3af;
  pointer-events: none;
}

.date-picker-row {
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  height: 88rpx;
  padding: 0 28rpx;
  border-radius: 20rpx;
  background: #fff;
}

.date-picker-txt {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  font-size: 28rpx;
  color: #111827;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.date-picker-ph {
  color: #9ca3af;
}

.date-picker-arrow {
  font-size: 36rpx;
  color: #9ca3af;
}

.cats {
  display: flex;
  flex-wrap: wrap;
  gap: 16rpx;
}

.cat {
  padding: 16rpx 32rpx;
  font-size: 26rpx;
  color: #374151;
  border: 1rpx solid #e5e7eb;
  border-radius: 999rpx;
  background: #fff;
}

.cat-on {
  color: #fff;
  background: #4a90e2;
  border-color: #4a90e2;
  box-shadow: 0 4rpx 12rpx rgba(74, 144, 226, 0.3);
}

.submit-dock {
  position: fixed;
  right: 0;
  bottom: calc(100rpx + env(safe-area-inset-bottom));
  left: 0;
  z-index: 49;
  padding: 16rpx 32rpx 20rpx;
  border-top: 1rpx solid #e5e7eb;
  background: #f9fafb;
}

.audit-banner {
  width: 100%;
  padding: 20rpx 0;
  margin: 0;
  border-radius: 0;
  background: #e8f4fd;
  box-sizing: border-box;
}

.audit-banner-txt {
  display: block;
  padding: 0;
  margin: 0;
  font-size: 22rpx;
  line-height: 1.5;
  color: #3b82c4;
  text-align: center;
}

.audit-banner-warn {
  background: #fef3c7;
}

.audit-banner-warn .audit-banner-txt {
  color: #92400e;
}

.submit {
  display: flex;
  width: 100%;
  height: 96rpx;
  align-items: center;
  justify-content: center;
  margin-top: 0;
  font-size: 30rpx;
  color: #fff;
  border-radius: 24rpx;
  background: linear-gradient(90deg, #4a90e2, #50c8d8);
  box-shadow: 0 8rpx 24rpx rgba(74, 144, 226, 0.25);
}

.submit-off {
  pointer-events: none;
  opacity: 0.45;
  box-shadow: none;
}

</style>
