<template>
  <!-- 通用列表页 -->
  <view 
    :class="[
      'common-list-page d-flex flex-column', 
      hasBg ? 'bg-base' : '',
      hasPadding ? 'p-3' : ''
    ]"
  >
    <view v-if="showTab && tabs" class="top-tab bg-base">
      <Tabs
        :tabs="tabs" 
        :width="700"
        v-model:currentIndex="tabCurrentIndex"
        :autoScroll="false"
        :defaultItemWidth="180"
        :autoItemWidth="tabsScrollable ? false : true"
        @click="handleTabClick"
      />
    </view>
    <!-- 搜索 -->
    <view v-if="showSearch && showList" class="d-flex flex-col">
      <SearchBar
        v-model="searchValue"
        placeholder="输入关键词搜索" 
        @search="doSearch"
        @cancel="doSearch"
      />
    </view>
    <!-- 下拉框 -->
    <view 
      v-if="dropDownNames.length > 0" 
      class="d-flex flex-row justify-between align-center mt-2"
      :class="[
        dropDownVisibleCount >= 3 ? 'justify-around' : ('justify-between')
      ]"
    >
      <template v-for="(drop, k) in dropDownNames" :key="k" >
        <SimpleDropDownPicker 
          v-if="!drop.activeTab || drop.activeTab.includes(tabCurrentId)"
          :modelValue="dropDownValues[k]"
          :columns="drop.options"
          :style="{maxWidth: `${100/dropDownVisibleCount}%`}"
          @update:modelValue="(v) => handleChangeDropDownValue(k, v)"
        />
      </template>
      <view 
        v-if="(showTotal && dropDownVisibleCount < 3 && dropDownVisibleCount != 0)" 
        class="d-flex flex-row align-center pt-3 pb-3 size-s color-primary text-bold"
      >
        <text>总共有 {{ listLoader.total }} 个</text>
      </view>
    </view>
    <view 
      v-if="showTotal && (dropDownVisibleCount >= 3 || dropDownVisibleCount == 0)" 
      class="d-flex flex-row justify-center align-center mt-3 size-s color-primary text-bold"
    >
      <text>总共有 {{ listLoader.total }} 个</text>
    </view>
    
    <!-- 列表 -->
    <slot name="list" :tabId="tabCurrentId" />
    <template v-if="showList">
      <view class="position-relative d-flex flex-row flex-wrap justify-between align-stretch mt-3">
        <view
          v-for="(item, i) in listLoader.list.value"
          :key="item.id"
          :class="[
            'position-relative d-flex flex-grow-1',
            itemType.endsWith('-2') ? 'width-1-2' : 'w-100'
          ]"
        >
          <Box2LineLargeImageUserShadow 
            v-if="itemType.startsWith('image-large')"
            class="w-100"
            titleColor="title-text"
            :classNames="getItemClass(i)"
            :image="getImage(item)"
            :titleBox="item.titleBox"
            :titlePrefix="item.titlePrefix"
            :title="item.title"
            :desc="item.desc"
            :tags="item.bottomTags"
            :badge="item.badge"
            @click="goDetails(item, item.id)"
          />
          <Box2LineImageRightShadow 
            v-else-if="itemType.startsWith('article-common')"
            class="w-100"
            titleColor="title-text"
            :titleBox="item.titleBox"
            :titlePrefix="item.titlePrefix"
            :classNames="getItemClass(i)"
            :image="getImage(item)"
            :title="item.title"
            :desc="item.desc"
            :tags="item.bottomTags"
            :badge="item.badge"
            :wideImage="true"
            @click="goDetails(item, item.id)"
          />
          <Box2LineImageRightShadow 
            v-else-if="itemType.startsWith('article-character')"
            class="w-100"
            :classNames="getItemClass(i)"
            :image="getImage(item)"
            titleColor="title-text"
            :title="item.title"
            :titlePrefix="item.titlePrefix"
            :titleBox="item.titleBox"
            :tags="item.bottomTags || item.keywords"
            :desc="item.desc"
            :badge="item.badge"
            @click="goDetails(item, item.id)"
          />
          <Box2LineImageRightShadow 
            v-else-if="itemType.startsWith('simple-text')"
            class="w-100"
            :classNames="getItemClass(i)"
            titleColor="title-text"
            :border="false"
            :showImage="false"
            :title="item.title"
            :titlePrefix="item.titlePrefix"
            :titleBox="item.titleBox"
            :tags="item.bottomTags || item.keywords"
            :desc="item.desc"
            :badge="item.badge"
            @click="goDetails(item, item.id)"
          />

        </view>
        <view v-if="itemType.endsWith('-2') && listLoader.list.value.length % 2 != 0" class="width-1-2" />
      </view>
      <SimplePageListLoader :loader="listLoader" />
    </template>
  </view>
</template>

<script setup lang="ts">
import { computed, nextTick, onMounted, ref, watch, type PropType } from 'vue';
import { useSimplePageListLoader } from '@/common/composeabe/SimplePageListLoader';
import { navTo } from '@/components/utils/PageAction';
import SimplePageListLoader from '@/common/components/SimplePageListLoader.vue';
import Box2LineLargeImageUserShadow from '@/pages/parts/Box2LineLargeImageUserShadow.vue';
import Box2LineImageRightShadow from '@/pages/parts/Box2LineImageRightShadow.vue';
import SimpleDropDownPicker, { type SimpleDropDownPickerItem } from '@/common/components/SimpleDropDownPicker.vue';
import AppCofig from '@/common/config/AppCofig';
import Tabs from '@/components/nav/Tabs.vue';
import SearchBar from '@/components/form/SearchBar.vue';
import { resolveCommonContentGetPageDetailUrlAuto } from './CommonContent';
import type { CommonListPageItemType } from './CommonListPage';

function getImage(item: any) {
  return item.thumbnail || item.image || AppCofig.defaultImage
}
function getItemClass(index: number) {
  return props.itemType.endsWith('-2') ? (index % 2 != 0 ? 'ml-1' : 'mr-1') : ''
}

export interface DropDownNames {
  /**
   * 下拉框选项
   */
  options: SimpleDropDownPickerItem[],
  /**
   * 默认选中值
   */
  defaultSelectedValue: number|string,
  /**
   * 显示Tab的ID
   */
  activeTab?: number[],
}
export interface CommonListItem extends Record<string, any>  {
  id: number,
  image: string,
  title: string,
}
export interface CommonListPageProps {
  /** 
   * 标题
   */
  title?: string
  /**
   * 分组标签
   */
  tabs?: { 
    id: number, 
    text: string,
    onlyJump?: boolean,
    jump?: () => void,
    width?: number,
  }[] | null
  /**
   * 标签是否可滚动
   * @default false
   */
  tabsScrollable?: boolean
  /**
   * 是否显示搜索框
   * @default true
   */
  showSearch?: boolean
  /**
   * 是否显示Tab
   * @default true
   */
  showTab?: boolean
  /**
   * 显示总数
   * @default false
   */
  showTotal?: boolean
  /**
   * 显示列表的Tab ID。默认所有Tab都显示列表。
   * @default undefined
   */
  showListTabIds?: number[]
  /**
   * 下拉框选项控制
   * @default []
   */
  dropDownNames?: DropDownNames[]
  /**
   * 列表项类型
   * @default 'article-common'
   */
  itemType?: CommonListPageItemType
  /**
   * 分页大小
   * @default 8
   */
  pageSize?: number
  /**
   * 加载数据函数
   * @param page 页码，从1开始
   * @param pageSize 分页大小
   * @param searchText 搜索文本
   * @param dropDownValues 下拉框值
   */
  load: (page: number, pageSize: number, searchText: string, dropDownValues: number[], tabSelect: number) => Promise<{ list: CommonListItem[], total: number }>
  /**
   * 点击详情跳转页面路径
   * 可以是字符串路径，也可以是对象数组，每个对象包含路径和参数
   * * 特殊值：byContent 表示根据 detailsPageByContentCallback 函数返回值跳转。
   */
  detailsPage?: string | Record<string, string|{
    page: string,
    params: Record<string, any>,
  }>
  /**
   * 根据内容项返回跳转路径的回调函数
   */
  detailsPageByContentCallback?: (item: any) => string
  /**
   * 详情跳转页面参数
   */
  detailsParams?: Record<string, any>
  /**
   * 是否有背景
   * @default true
   */
  hasBg?: boolean
  /**
   * 是否有内边距
   * @default true
   */
  hasPadding?: boolean
  /**
   * 起始标签索引
   * @default 0
   */
  startTabIndex?: number | undefined
  /**
   * 挂载时是否加载数据
   * @default true
   */
  loadMounted?: boolean
}

const props = withDefaults(defineProps<CommonListPageProps>(), {
  title: '',
  tabs: null,
  tabsScrollable: false,
  showSearch: true,
  showTab: true,
  showTotal: false,
  dropDownNames: () => [],
  detailsPageByContentCallback: resolveCommonContentGetPageDetailUrlAuto,
  itemType: 'article-common',
  pageSize: 8,
  detailsPage: '/pages/article/details',
  detailsParams: () => ({}),
  hasBg: true,
  hasPadding: true,
  startTabIndex: undefined,
  loadMounted: true,
})

const emit = defineEmits([ 'goCustomDetails' ])

const dropDownVisibleCount = computed(() => {
  let c = 0;
  for (const element of props.dropDownNames) {
    if (!element.activeTab || element.activeTab.includes(tabCurrentId.value))
      c++;
  }
  return c;
})
const dropDownValues = ref<any>([]);
const searchValue = ref('');
const listLoader = useSimplePageListLoader(props.pageSize, async (page, pageSize) => {
  return await props.load(
    page, pageSize, 
    searchValue.value,
    getDropDownValues(),
    props.tabs?.[tabCurrentIndex.value]?.id ?? tabCurrentIndex.value,
  )
});
const tabCurrentIndex = ref(0)
const tabCurrentId = computed(() => props.tabs?.[tabCurrentIndex.value]?.id ?? -1)
const showList = computed(() => !props.showListTabIds || props.showListTabIds.includes(tabCurrentId.value))


function getDropDownValues() {
  const result = [] as number[];
  let c = 0;
  for (const element of props.dropDownNames) {
    if (!element.activeTab || element.activeTab.includes(tabCurrentId.value))
      result.push(dropDownValues.value[c]);
    c++;
  }
  return result;
}
function handleChangeDropDownValue(index: number, value: number) {
  dropDownValues.value[index] = value;
  listLoader.loadData(undefined, true);
}
function handleTabClick(e: any) {
  nextTick(() => {
    if (e.jump) {
      e.jump?.();
      tabCurrentIndex.value = 0;
      return;
    }
    listLoader.loadData(undefined, true);
  })
}
function doSearch() {
  listLoader.loadData(undefined, true);
}
function goDetails(item: any, id: number) {
  if (props.detailsPage == 'disabled') 
    return;
  if (props.detailsPage == 'custom') {
    emit('goCustomDetails', item, id)
    return;
  }
  if (props.detailsPage == 'byContent') {
    if (handleByContent())
      return;
  }

  function handleByContent() {
    const page = props.detailsPageByContentCallback?.(item);
    if (page) {
      navTo(page, { 
        ...props.detailsParams, 
        id 
      })
      return true; 
    }
    return false;
  }

  const page = typeof props.detailsPage === 'object' ? props.detailsPage[tabCurrentId.value] : undefined;
  if (page) {
    if (typeof page === 'string') {
      if (page == 'byContent' && handleByContent())
        return;
      navTo(page, { 
        ...props.detailsParams, 
        id 
      })
      return; 
    }
    if (typeof page === 'object') {
      const item = page as {
        page: string,
        params: Record<string, any>,
      };
      if (item.page == 'byContent' && handleByContent())
        return;
      navTo(item.page, { 
        ...item.params, 
        id 
      })
      return; 
    }
  } else if (typeof props.detailsPage === 'object') {
    if (handleByContent())
      return;
    navTo('/pages/article/details', { 
      ...props.detailsParams,
      id
    })
    return;
  }
  navTo(props.detailsPage as string, { 
    ...props.detailsParams,
    id
  })
}

function loadDropDownValues() {
  dropDownValues.value = [];
  for (const element of props.dropDownNames) {
    dropDownValues.value.push(element.defaultSelectedValue);
  }
}

watch(tabCurrentIndex, () => {
  listLoader.loadData(undefined, true);
});
watch(() => props.startTabIndex, () => {
  if (props.startTabIndex) {
    tabCurrentIndex.value = props.startTabIndex;
  }
});
watch(() => props.dropDownNames.length, () => {
  loadDropDownValues();
  listLoader.loadData(undefined, true);
});

defineExpose({
  load: () => {
    listLoader.loadData(undefined, true);
  },
})

onMounted(() => {
  if (props.startTabIndex)
    tabCurrentIndex.value = props.startTabIndex;
  if (props.title)
    uni.setNavigationBarTitle({ title: props.title, })
  loadDropDownValues();
  setTimeout(() => {
    if (props.loadMounted && showList.value) {
      listLoader.loadData(undefined, true);
    }
  }, 500);
});
</script>

<style lang="scss">
.common-list-page {
  min-height: 100vh; 
}
</style>