<script setup lang="ts">
import { debounce } from "throttle-debounce";
import Config from "@/config";
import usePage from "@/hooks/usePage";
import {
  appRecipeCategoryListGet,
  appCollectCollectPost,
  appMerchantCartAddCartPost,
  getDishListByCategoryId,
} from "@/service";
import { CollectionType } from "@/constant/enums";
import {
  useCategoryNavStore,
  useConfigStore,
  useUserStore,
} from "@/store";
import { formatSalesCount } from "@/utils/utils";
import { onShow } from "@dcloudio/uni-app";

const { t } = useI18n();
const configStore = useConfigStore();
const userStore = useUserStore();
const categoryNavStore = useCategoryNavStore();

/** 菜品瀑布流项（接口字段较多，用宽松类型避免模板断言） */
type DishGridItem = Record<string, any>;

/** 菜谱分类（与首页 class-bullet 同源：appRecipeCategoryListGet） */
const recipeCategoryList = ref<Record<string, unknown>[]>([]);
/** 当前选中的菜谱分类 id，仅由用户点击大分类或首页写入的 pending 决定，不用路由 options */
const recipeCategoryId = ref<string>("");

/** 横向分类 scroll-view 滚动到选中项（与 :id="'recipe-cat-'+id" 对应） */
const recipeCategoryScrollInto = ref("");

const pageReady = ref(false);

const { paging, dataList, queryList } = usePage(getList);

function getList(pageNum: number, pageSize: number) {
  return new Promise<{ rows: unknown[]; total?: number }>((resolve) => {
    const rid = recipeCategoryId.value;
    if (!rid) {
      resolve({ rows: [], total: 0 });
      return;
    }

    getDishListByCategoryId({
      params: {
        pageNum,
        pageSize,
        recipeCategoryId: rid,
      },
      body: {
        pageNum,
        pageSize,
        lat: userStore.userLocation.latitude || undefined,
        lng: userStore.userLocation.longitude || undefined,
        recipeCategoryId: rid,
        merchantCategoryIds: [],
        merchantLabelIds: [],
      },
    })
      .then((res: any) => {
        resolve({
          rows: res?.rows ?? res?.data?.rows ?? [],
          total: res?.total ?? res?.data?.total,
        });
      })
      .catch(() => resolve({ rows: [] }));
  });
}

const dishColumns = computed(() => {
  const list = (dataList.value || []) as DishGridItem[];
  return [
    list.filter((_, i) => i % 2 === 0),
    list.filter((_, i) => i % 2 === 1),
  ];
});

function getDishPromoLabel(item: DishGridItem): string {
  const raw =
    item.marketingLabel ??
    item.hotSaleTag ??
    item.rankTag ??
    item.promotionLabel;
  return typeof raw === "string" && raw.trim() ? raw.trim() : "";
}

function isSoldOutStock(stockLike: unknown) {
  const n = Number(stockLike);
  return !Number.isNaN(n) && n <= 0;
}

function navigateToDishes(item: DishGridItem) {
  const id = item?.id;
  const storeId = item?.merchantId;
  if (id == null || storeId == null) return;
  uni.navigateTo({
    url: `/pages-store/pages/store/dishes?id=${id}&storeId=${storeId}`,
  });
}

function goSearch() {
  uni.navigateTo({ url: "/pages/search/index" });
}

function goCart() {
  uni.navigateTo({ url: "/pages-user/pages/cart/index" });
}

function handleBack() {
  const pages = getCurrentPages?.() || [];
  if (pages.length <= 1) {
    uni.switchTab({ url: "/pages/home/index" });
    return;
  }
  uni.navigateBack();
}

const cartBadgeTotal = computed(() => {
  const list = userStore.userCartAllData;
  if (!Array.isArray(list) || list.length === 0) return 0;
  let n = 0;
  for (const m of list) {
    n +=
      (m as { merchantCartVoList?: unknown[] })?.merchantCartVoList
        ?.length || 0;
  }
  return n;
});

const addingDishId = ref<string | number | null>(null);

async function onAddCartClick(item: DishGridItem) {
  if (isSoldOutStock(item?.stock)) {
    uni.showToast({
      title: t("common.prompt.soldOut"),
      icon: "none",
    });
    return;
  }
  if (!userStore.isLogin) {
    uni.showToast({ title: t("common.pleaseLogin"), icon: "none" });
    setTimeout(() => uni.navigateTo({ url: Config.loginPath }), 400);
    return;
  }
  const dishId = item?.id;
  const merchantId = item?.merchantId;
  if (dishId == null || merchantId == null) return;
  if (addingDishId.value != null) return;
  addingDishId.value = dishId as string | number;
  try {
    await appMerchantCartAddCartPost({
      body: {
        merchantId,
        dishId,
        count: 1,
        merchantCartSideDishBoList: [],
      } as any,
    });
    uni.showToast({ title: t("toast.addCartSuccess"), icon: "none" });
    userStore.getUserCartAllData();
  } finally {
    addingDishId.value = null;
  }
}

const debouncedCollect = debounce(
  1300,
  (
    isCollected: boolean,
    id: string,
    type: CollectionType,
    cb: () => void
  ) => {
    appCollectCollectPost({
      body: { targetId: id, targetType: type },
    }).then(() => cb());
  },
  { atBegin: true }
);

function handleDishCollectionClick(item: DishGridItem) {
  if (!userStore.isLogin) {
    uni.showToast({ title: t("common.pleaseLogin"), icon: "none" });
    setTimeout(() => uni.navigateTo({ url: Config.loginPath }), 400);
    return;
  }
  const id = String(item?.id ?? "");
  if (!id) return;
  debouncedCollect(Boolean(item.isCollect), id, CollectionType.DISH, () => {
    item.isCollect = !item.isCollect;
  });
}

function normalizeCategoryId(v: unknown): string {
  if (v === null || v === undefined) return "";
  return String(v).trim();
}

/** 与列表项 id 比对（兼容数字 / 字符串） */
function categoryRowIdEquals(
  cat: Record<string, unknown>,
  target: string
): boolean {
  const t = normalizeCategoryId(target);
  if (!t) return false;
  const a = normalizeCategoryId(cat.id);
  if (a === t) return true;
  const na = Number(a);
  const nt = Number(t);
  if (!Number.isNaN(na) && !Number.isNaN(nt) && na === nt) return true;
  return false;
}

/** 在接口返回的分类列表中解析应选中的 id（与首页点击项对齐） */
function resolveRecipeCategoryIdFromPending(pendingRaw: string | null): string {
  const list = recipeCategoryList.value;
  if (!list.length) return "";

  const pending = pendingRaw ? normalizeCategoryId(pendingRaw) : "";
  if (pending) {
    const hit = list.find((c) => categoryRowIdEquals(c, pending));
    if (hit != null) return normalizeCategoryId(hit.id);
  }
  return normalizeCategoryId(list[0].id);
}

function scrollRecipeTabIntoView() {
  const id = recipeCategoryId.value;
  if (!id) return;
  recipeCategoryScrollInto.value = "";
  nextTick(() => {
    recipeCategoryScrollInto.value = `recipe-cat-${id}`;
  });
}

function onSelectRecipe(cat: Record<string, unknown>) {
  const id = normalizeCategoryId(cat?.id);
  if (!id || id === recipeCategoryId.value) return;
  recipeCategoryId.value = id;
  nextTick(() => scrollRecipeTabIntoView());
  paging.value?.reload();
}

async function loadRecipeCategories() {
  const recipeRes: any = await appRecipeCategoryListGet({});
  recipeCategoryList.value = recipeRes?.data || [];
}

function resolveInitialRecipeCategoryId() {
  const pending = categoryNavStore.consumePendingRecipeCategoryId();
  recipeCategoryId.value = resolveRecipeCategoryIdFromPending(pending);
}

onMounted(async () => {
  await loadRecipeCategories();
  resolveInitialRecipeCategoryId();
  pageReady.value = true;
  nextTick(() => {
    scrollRecipeTabIntoView();
    paging.value?.reload();
  });
});

onShow(() => {
  userStore.getUserCartAllData();
});
</script>

<template>
  <z-paging
    ref="paging"
    v-model="dataList"
    :auto="false"
    @query="queryList"
    bg-color="#f5f5f5"
  >
    <template #top>
      <view class="cat-top" :style="{ paddingTop: configStore.statusBarHeight + 'px' }">
        <view class="cat-header-row">
          <view class="cat-icon-btn" @click="handleBack">
            <view class="i-carbon:chevron-left text-40rpx text-#111" />
          </view>
          <view class="cat-search" @click="goSearch">
            <image
              src="@img/chef/100222.png"
              class="cat-search-icon"
              mode="aspectFit"
            />
            <text class="cat-search-placeholder">{{
              t("components.search.placeholder")
            }}</text>
          </view>
          <view class="cat-icon-btn cat-icon-btn--cart" @click="goCart">
            <view class="i-carbon:shopping-cart text-34rpx text-#14181b" />
            <view
              v-if="userStore.isLogin && cartBadgeTotal > 0"
              class="cat-cart-badge"
              >{{ cartBadgeTotal > 99 ? "99+" : cartBadgeTotal }}</view
            >
          </view>
        </view>

        <!-- 第一行：菜谱分类（圆图 + 文案） -->
        <scroll-view
          class="cat-scroll-x"
          scroll-x
          scroll-with-animation
          :scroll-into-view="recipeCategoryScrollInto"
          :show-scrollbar="false"
          enable-flex
        >
          <view class="cat-recipe-track">
            <view
              v-for="cat in recipeCategoryList"
              :key="String(cat.id)"
              :id="'recipe-cat-' + String(cat.id)"
              class="cat-recipe-item"
              @click="onSelectRecipe(cat)"
            >
              <view
                class="cat-recipe-ring"
                :class="{
                  'cat-recipe-ring--on': categoryRowIdEquals(
                    cat,
                    recipeCategoryId,
                  ),
                }"
              >
                <image
                  class="cat-recipe-img"
                  :src="String(cat.categoryImageUrl || cat.categoryImage || '')"
                  mode="aspectFill"
                />
              </view>
              <text
                class="cat-recipe-label"
                :class="{
                  'cat-recipe-label--on': categoryRowIdEquals(
                    cat,
                    recipeCategoryId,
                  ),
                }"
                >{{ cat.categoryName }}</text
              >
            </view>
          </view>
        </scroll-view>
      </view>
    </template>

    <view v-if="pageReady" class="cat-waterfall px-24rpx pb-32rpx">
      <view class="waterfall-row flex gap-16rpx items-start">
        <view
          v-for="(col, colIndex) in dishColumns"
          :key="colIndex"
          class="waterfall-col flex-1 min-w-0 flex flex-col gap-16rpx"
        >
          <view
            v-for="item in col"
            :key="String(item.id) + '-' + String(item.merchantId)"
            class="cat-dish-card w-full"
            @click="navigateToDishes(item)"
          >
            <view class="cat-dish-image relative w-full bg-#f0f0f0">
              <view v-if="item.isNew == 1" class="dish-new-ribbon">
                <text class="dish-new-ribbon__text">NEW</text>
              </view>
              <view
                class="cat-dish-collect"
                @click.stop="handleDishCollectionClick(item)"
              >
                <image
                  v-if="!item.isCollect"
                  src="@img-store/1334.png"
                  mode="aspectFit"
                  class="cat-dish-collect-icon"
                />
                <image
                  v-else
                  src="@img-store/1337.png"
                  mode="aspectFit"
                  class="cat-dish-collect-icon"
                />
              </view>
              <view
                v-if="isSoldOutStock(item.stock)"
                class="cat-dish-soldout"
                >{{ t("common.prompt.soldOut") }}</view
              >
              <image
                :src="String(item.dishImage || '').split(',')[0]"
                mode="widthFix"
                class="w-full block"
              />
            </view>
            <view class="cat-dish-body">
              <view class="cat-dish-meta flex items-start justify-between gap-12rpx mb-14rpx">
                <view class="min-w-0 flex-1">
                  <text class="cat-dish-price"
                    >US${{ item.discountPrice }}</text
                  >
                  <text
                    v-if="
                      Number(item.originalPrice) > Number(item.discountPrice)
                    "
                    class="cat-dish-original"
                    >US${{ item.originalPrice }}</text
                  >
                </view>
                <text class="cat-dish-sales shrink-0"
                  >{{ t("pages-store.store.sales") }}:
                  {{ formatSalesCount(item.salesCount) }}</text
                >
              </view>
              <view class="cat-dish-title line-clamp-2 mb-16rpx">{{
                item.dishName
              }}</view>
              <view class="flex items-center justify-between gap-12rpx">
                <view
                  v-if="Number(item.memberPrice) > 0"
                  class="cat-dish-member shrink min-w-0"
                >
                  <text class="cat-dish-member-inner"
                    >{{ t("pages-store.store.members") }}: US${{
                      item.memberPrice
                    }}</text
                  >
                </view>
                <view v-else class="flex-1 min-w-0" />
                <view
                  class="cat-dish-add center shrink-0"
                  :class="{
                    'cat-dish-add--busy': addingDishId === item.id,
                  }"
                  @click.stop="onAddCartClick(item)"
                >
                  <image src="@img/chef/1285.png" class="w-28rpx h-28rpx" />
                </view>
              </view>
              <view
                v-if="getDishPromoLabel(item)"
                class="cat-dish-promo mt-16rpx"
              >
                <text class="cat-dish-promo-text">{{
                  getDishPromoLabel(item)
                }}</text>
              </view>
            </view>
          </view>
        </view>
      </view>
    </view>

    <template #bottom>
      <view class="h-24rpx" />
      <view :style="[configStore.iosSafeBottomPlaceholder]" />
    </template>
  </z-paging>
</template>

<style scoped lang="scss">
.cat-top {
  background: #f5f5f5;
  padding-bottom: 8rpx;
}

.cat-header-row {
  display: flex;
  align-items: center;
  gap: 16rpx;
  padding: 12rpx 24rpx 20rpx;
}

.cat-icon-btn {
  width: 72rpx;
  height: 72rpx;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.cat-icon-btn--cart {
  position: relative;
}

.cat-cart-badge {
  position: absolute;
  top: 2rpx;
  right: 2rpx;
  min-width: 28rpx;
  height: 28rpx;
  padding: 0 6rpx;
  font-size: 18rpx;
  line-height: 28rpx;
  font-weight: 600;
  color: #fff;
  text-align: center;
  background: #e23636;
  border-radius: 999rpx;
}

.cat-search {
  flex: 1;
  min-width: 0;
  height: 72rpx;
  border-radius: 36rpx;
  background: #fff;
  box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.06);
  display: flex;
  align-items: center;
  padding: 0 28rpx;
}

.cat-search-icon {
  width: 28rpx;
  height: 28rpx;
  flex-shrink: 0;
}

.cat-search-placeholder {
  margin-left: 16rpx;
  font-size: 28rpx;
  font-weight: 500;
  color: #999;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cat-scroll-x {
  width: 100%;
  white-space: nowrap;
}

.cat-recipe-track {
  display: inline-flex;
  flex-direction: row;
  padding: 8rpx 24rpx 16rpx;
  gap: 36rpx;
}

.cat-recipe-item {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  width: 120rpx;
  flex-shrink: 0;
}

.cat-recipe-ring {
  width: 102rpx;
  height: 102rpx;
  border-radius: 50%;
  padding: 0;
  background: #fff;
  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.07);
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
}

.cat-recipe-ring--on {
  border: 4rpx solid #14181b;
}

.cat-recipe-img {
  width: 94rpx;
  height: 94rpx;
  border-radius: 50%;
}

.cat-recipe-label {
  margin-top: 12rpx;
  font-size: 22rpx;
  line-height: 1.2;
  color: #333;
  text-align: center;
  width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 500;
}

.cat-recipe-label--on {
  color: #14181b;
  font-weight: 600;
}

.cat-waterfall {
  min-height: 200rpx;
}

.cat-dish-card {
  background: #fff;
  border-radius: 24rpx;
  overflow: hidden;
  box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06);
}

.cat-dish-collect {
  position: absolute;
  z-index: 2;
  top: 12rpx;
  right: 12rpx;
  width: 56rpx;
  height: 56rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}

.cat-dish-collect-icon {
  width: 44rpx;
  height: 44rpx;
  filter: drop-shadow(0 2rpx 6rpx rgba(0, 0, 0, 0.18));
}

.cat-dish-soldout {
  position: absolute;
  z-index: 2;
  left: 16rpx;
  top: 16rpx;
  padding: 0 14rpx;
  height: 48rpx;
  border-radius: 24rpx;
  background: rgba(20, 24, 27, 0.75);
  color: #fff;
  font-size: 24rpx;
  font-weight: 500;
  display: flex;
  align-items: center;
  justify-content: center;
}

.cat-dish-body {
  padding: 20rpx 20rpx 22rpx;
}

.cat-dish-price {
  color: #e02e24;
  font-size: 32rpx;
  font-weight: 600;
  line-height: 1.2;
}

.cat-dish-original {
  margin-left: 10rpx;
  color: #b3b3b3;
  font-size: 22rpx;
  text-decoration: line-through;
  vertical-align: baseline;
}

.cat-dish-sales {
  color: #999;
  font-size: 24rpx;
  line-height: 1.35;
  max-width: 48%;
  text-align: right;
}

.cat-dish-title {
  color: #1a1a1a;
  font-size: 28rpx;
  font-weight: 500;
  line-height: 1.45;
}

.cat-dish-member {
  display: inline-flex;
  align-items: center;
  max-width: calc(100% - 88rpx);
}

.cat-dish-member-inner {
  display: inline-block;
  padding: 6rpx 18rpx;
  border-radius: 999rpx;
  background: linear-gradient(180deg, #fff5eb 0%, #ffe8d6 100%);
  color: #c45c1a;
  font-size: 24rpx;
  font-weight: 500;
  line-height: 1.35;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}

.cat-dish-add {
  width: 56rpx;
  height: 56rpx;
  border-radius: 50%;
  background: #14181b;
  box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.12);
}

.cat-dish-add--busy {
  opacity: 0.45;
  pointer-events: none;
}

.cat-dish-promo {
  padding: 12rpx 16rpx;
  border-radius: 12rpx;
  background: #fff0f0;
}

.cat-dish-promo-text {
  color: #e02e24;
  font-size: 22rpx;
  font-weight: 500;
  line-height: 1.4;
}

.dish-new-ribbon {
  position: absolute;
  top: 0;
  left: 0;
  width: 184rpx;
  height: 184rpx;
  overflow: hidden;
  z-index: 5;
  pointer-events: none;

  &__text {
    position: absolute;
    top: 26rpx;
    left: -66rpx;
    width: 240rpx;
    text-align: center;
    font-size: 22rpx;
    font-weight: 700;
    color: #fff;
    letter-spacing: 2rpx;
    line-height: 44rpx;
    background: #E23636;
    transform: rotate(-45deg);
  }
}
</style>
