<script lang="ts" setup>
/**
 * 挂号订单管理页
 *
 * 支持「列表 / 卡片」双视图切换（通用 ViewModeSwitch + useViewMode 记忆偏好）：
 * - 搜索表单从 grid 内嵌拆出为顶部统一 SearchForm，双视图共用同一份条件
 * - 新增就诊人/医生关键字、挂号类型、支付/挂号/退款状态筛选
 * - 点击卡片或行内「详情」打开挂号详情弹窗（就诊人/用户/诊所/医生/挂号方式/价格）
 */
import type { VbenFormProps } from '#/adapter/form';
import type { VxeGridListeners } from '#/adapter/vxe-table';

import { ref, watch } from 'vue';
import { useRoute } from 'vue-router';

import { Page, useVbenModal } from '@vben/common-ui';

import { Button, Image, Tag } from 'ant-design-vue';

import { useVbenForm } from '#/adapter/form';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { TableAction } from '#/components/table-action';
import { useViewMode, ViewModeSwitch } from '#/components/view-mode-switch';
import StoreCardModal from '#/components/store-card/StoreCardModal.vue';
import PrescriptionDetail from '#/views/doctor/doctor-reception/components/PrescriptionDetail.vue';

import { getRegisterListApi } from './api';
import Refund from './components/refund.vue';
import RegisterDetailModal from './components/RegisterDetailModal.vue';
import RegisterOrderCardList from './components/RegisterOrderCardList.vue';
import {
  REGISTER_REFUND_STATUS_MAP,
  REGISTER_STATUS_MAP,
  REGISTER_TYPE_MAP,
} from './config/constants';
import { formOptions } from './config/search';
import { gridOptions } from './config/table';

const route = useRoute();
const hasTopTableDropDownActions = ref(false);

/** 列表/卡片双视图：通用 useViewMode 自带 localStorage 记忆 */
const viewMode = useViewMode('register-order-view-mode');
const cardListRef = ref<InstanceType<typeof RegisterOrderCardList> | null>(null);

const gridEvents: VxeGridListeners<any> = {
  checkboxChange() {
    const records = gridApi.grid.getCheckboxRecords();
    hasTopTableDropDownActions.value = records.length > 0;
  },
  checkboxAll() {
    const records = gridApi.grid.getCheckboxRecords();
    hasTopTableDropDownActions.value = records.length > 0;
  },
};

/**
 * 从路由 query 生成带默认值的表单配置
 * 商品订单页「挂号金额」跳转会带 order_no，写进 schema defaultValue 让双视图首屏直接生效
 */
function buildFormOptionsFromRoute(): VbenFormProps {
  const raw = route.query.order_no;
  const orderNo = Array.isArray(raw) ? raw[0] : raw;
  if (!orderNo) {
    return formOptions;
  }
  const schema = (formOptions.schema ?? []).map((item) => {
    if (item.fieldName === 'order_no') {
      return { ...item, defaultValue: String(orderNo) };
    }
    // 指定订单号查询时放开默认时间范围，避免历史订单被本月范围滤掉
    if (item.fieldName === 'search_time') {
      return { ...item, defaultValue: null };
    }
    return item;
  });
  return { ...formOptions, schema };
}

/** 生效的搜索表单配置（含路由 order_no 默认值注入） */
const effectiveFormOptions = buildFormOptionsFromRoute();

/**
 * 从 schema 提取 defaultValue 作为首屏搜索条件
 * 双视图首屏都要带默认时间范围，保证查询口径与表单显示一致
 */
function collectDefaultSearchValues(): Record<string, any> {
  const values: Record<string, any> = {};
  for (const item of effectiveFormOptions.schema ?? []) {
    if (item.fieldName && item.defaultValue !== undefined) {
      values[item.fieldName] = item.defaultValue;
    }
  }
  return values;
}

/** 列表与卡片共用的搜索条件（提交/重置时整体替换，卡片靠 watch 自动拉数） */
const searchValues = ref<Record<string, any>>(collectDefaultSearchValues());

/**
 * 顶部统一搜索表单（从 grid 内嵌表单抽出，双视图共用）
 * 列表模式提交后 reload 回第 1 页；卡片模式由 formValues watch 自动拉数
 */
const [SearchForm, searchFormApi] = useVbenForm({
  ...effectiveFormOptions,
  handleSubmit: async (values) => {
    searchValues.value = { ...(values || {}) };
    if (viewMode.value === 'list') {
      gridApi.reload();
    }
  },
  handleReset: async () => {
    // 自定义 handleReset 会接管默认行为，必须手动还原控件到 defaultValue（reset 为新 API，resetForm 已弃用）
    await searchFormApi.reset();
    searchValues.value = collectDefaultSearchValues();
    if (viewMode.value === 'list') {
      gridApi.reload();
    }
  },
});

const [Grid, gridApi] = useVbenVxeGrid({
  gridOptions: {
    ...gridOptions,
    // 搜索已抽出为顶部统一表单，关闭 grid 自带的表单开关按钮
    toolbarConfig: { ...gridOptions.toolbarConfig, search: false },
    proxyConfig: {
      ajax: {
        /** 始终合并顶部统一搜索条件 */
        query: async ({ page }: { page: { currentPage: number; pageSize: number } }) => {
          return await getRegisterListApi({
            page: page.currentPage,
            pageSize: page.pageSize,
            ...searchValues.value,
          });
        },
      },
    },
  },
  gridEvents,
});

// 记忆持久化由 useViewMode 内部完成；切回列表时 grid 被 v-if 卸载过需主动重查
watch(viewMode, (mode, prev) => {
  if (mode === 'list' && prev === 'card') {
    gridApi.query();
  }
});

/** 操作成功后的视图刷新：列表保当前页，卡片原地重拉已加载范围 */
async function refreshCurrentView() {
  await (viewMode.value === 'list'
    ? gridApi.query()
    : cardListRef.value?.refreshKeepPage?.());
}

/** 回第 1 页的强刷新（退款弹窗内部 reload 语义） */
function refreshCurrentViewFromPageOne() {
  if (viewMode.value === 'list') {
    gridApi.reload();
  } else {
    cardListRef.value?.reload?.();
  }
}

/**
 * 传给退款弹窗的 gridApi 代理：弹窗内部只会调 reload()/query()，
 * 卡片模式下需要转发给卡片列表，故不能直接把 gridApi 传进去
 */
const gridApiProxy = {
  reload: () => refreshCurrentViewFromPageOne(),
  query: () => refreshCurrentView(),
};

const [StoreCardModalComp, StoreCardModalApi] = useVbenModal({
  connectedComponent: StoreCardModal,
});

function openStoreCard(storeId?: number) {
  if (!storeId) return;
  StoreCardModalApi.setData({ storeId: Number(storeId) });
  StoreCardModalApi.open();
}

const [PrescriptionDetailModal, PrescriptionDetailModalApi] = useVbenModal({
  connectedComponent: PrescriptionDetail,
});

const [RefundModal, RefundModalApi] = useVbenModal({
  connectedComponent: Refund,
});

/** 挂号详情弹窗：列表行「详情」与卡片点击共用 */
const [RegisterDetailModalComp, registerDetailModalApi] = useVbenModal({
  connectedComponent: RegisterDetailModal,
});

function openRegisterDetail(row: Record<string, any>) {
  registerDetailModalApi.setData({ row });
  registerDetailModalApi.open();
}

function openPrescriptionDetail(id: number) {
  PrescriptionDetailModalApi.setData({
    values: id,
  });
  PrescriptionDetailModalApi.open();
}

function openRefundModal(id: number) {
  RefundModalApi.setData({
    values: {
      register_id: id,
    },
    gridApi: gridApiProxy,
  });
  RefundModalApi.open();
}

function canRefund(row: Record<string, any>) {
  return row.is_pay === 1 && row.refund_status !== 1 && row.refund_status !== 3;
}

function formatRegisterPrice(price: unknown) {
  const n = Number(price);
  if (!Number.isFinite(n)) {
    return '—';
  }
  return `¥${n.toFixed(2)}`;
}

/** 列表槽用元数据取值 helper：v-if 双重索引无法类型收窄，统一在这里兜底 */
function rowTypeMeta(row: Record<string, any>) {
  return REGISTER_TYPE_MAP[Number(row?.type)] ?? null;
}
function rowStatusMeta(row: Record<string, any>) {
  return REGISTER_STATUS_MAP[Number(row?.status)] ?? null;
}
function rowRefundMeta(row: Record<string, any>) {
  return (
    REGISTER_REFUND_STATUS_MAP[Number(row?.refund_status ?? 0)] ?? {
      label: '未退款',
      color: 'default',
    }
  );
}
</script>

<template>
  <Page auto-content-height title="订单管理">
    <PrescriptionDetailModal />
    <RefundModal />
    <StoreCardModalComp />
    <!-- 挂号详情弹窗：处方号/诊所名点击透传到已有弹窗 -->
    <RegisterDetailModalComp
      @open-prescription="openPrescriptionDetail"
      @open-store="openStoreCard"
    />
    <!-- 顶部统一搜索（双视图共用，替代原 grid 内嵌表单） -->
    <div class="mb-3 rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--card,var(--background)))] p-3">
      <SearchForm />
    </div>
    <!-- 视图切换：列表 / 卡片看板 -->
    <div class="mb-3 flex items-center justify-between gap-3">
      <ViewModeSwitch v-model="viewMode" />
    </div>
    <Grid v-if="viewMode === 'list'">
      <template #toolbar-actions>
        <TableAction :actions="[]" :drop-down-actions="[]">
          <template #more>
            <Button style="margin-left: 16px">
              批量操作
            </Button>
          </template>
        </TableAction>
      </template>
      <template #store-name="{ row }">
        <Button
          v-if="row.store?.id || row.store_id"
          type="link"
          size="small"
          class="!px-0"
          @click="openStoreCard(row.store?.id || row.store_id)"
        >
          {{ row.store?.name || '—' }}
        </Button>
        <span v-else>{{ row.store?.name || '—' }}</span>
      </template>
      <template #prescription="{ row }">
        <div v-for="item in row.prescription" :key="item.id">
          <Button type="link" @click="openPrescriptionDetail(item.id)">
            {{ item.prescription_no }}
          </Button>
        </div>
      </template>
      <template #salesperson="{ row }">
        <div v-if="row.salesperson?.id" class="flex items-center gap-2 text-sm">
          <Image
            :src="row.salesperson.avatar || '/img/user-default-avatar.png'"
            :width="28"
            :height="28"
            class="rounded-full object-cover"
          />
          <span>{{ row.salesperson.nick_name || '—' }}</span>
        </div>
        <span v-else class="text-sm text-gray-500">无推广员</span>
      </template>
      <template #price="{ row }">
        <span>{{ formatRegisterPrice(row.price) }}</span>
      </template>
      <template #is_pay="{ row }">
        <Tag :color="row.is_pay === 1 ? 'green' : 'red'">
          {{ row.is_pay === 1 ? '已支付' : '未支付' }}
        </Tag>
      </template>
      <template #refund_status="{ row }">
        <!-- 退款状态渲染统一走 constants 映射，与卡片/详情同语义 -->
        <Tag :color="rowRefundMeta(row).color">
          {{ rowRefundMeta(row).label }}
        </Tag>
      </template>
      <template #type="{ row }">
        <Tag v-if="rowTypeMeta(row)" :color="rowTypeMeta(row)!.color">
          {{ rowTypeMeta(row)!.label }}
        </Tag>
        <Tag v-else color="default">未知</Tag>
      </template>
      <template #status="{ row }">
        <Tag v-if="rowStatusMeta(row)" :color="rowStatusMeta(row)!.color">
          {{ rowStatusMeta(row)!.label }}
        </Tag>
      </template>
      <template #toolbar-tools></template>
      <template #action="{ row }">
        <TableAction
          :actions="[
            {
              label: '详情',
              type: 'link',
              icon: 'marketeq:eye',
              onClick: openRegisterDetail.bind(null, row),
            },
            {
              label: '退款',
              type: 'link',
              icon: 'mingcute:refund-dollar-fill',
              ifShow: canRefund(row),
              onClick: openRefundModal.bind(null, row.id),
            },
          ]"
          :drop-down-actions="[]"
        />
      </template>
    </Grid>
    <!-- 卡片看板视图：展示内容与列表一致，点卡片看详情，弹窗复用父级 -->
    <div v-else class="rg-card-wrap">
      <RegisterOrderCardList
        ref="cardListRef"
        :form-values="searchValues"
        :can-refund="canRefund"
        @open-detail="openRegisterDetail"
        @refund="openRefundModal"
        @open-prescription="openPrescriptionDetail"
        @open-store="openStoreCard"
      />
    </div>
  </Page>
</template>

<style scoped lang="scss">
/* 卡片看板容器：撑满剩余高度，内部滚动（收起态搜索一行 + 切换行约 170px，min-height 兜底） */
.rg-card-wrap {
  height: calc(100% - 170px);
  min-height: 420px;
}
</style>
