<script setup lang="ts">
/**
 * 医生端 PC 传方入口：顶栏按钮 + 子窗口列表 + 状态操作
 * 权限：有 doctor_id 且绑定 store_id 时由外层 v-if 控制，本组件只负责展示与操作
 */
import {
  computed,
  onBeforeUnmount,
  onMounted,
  ref,
  watch,
} from 'vue';

import {
  FileTextOutlined,
  ReloadOutlined,
  ZoomInOutlined,
  ZoomOutOutlined,
} from '@ant-design/icons-vue';
import { usePreferences } from '@vben/preferences';
import { useUserStore } from '@vben/stores';

import {
  Badge,
  Button,
  Dropdown,
  Image,
  Input,
  Menu,
  Modal,
  Select,
  Spin,
  Tag,
  Textarea,
  Tooltip,
  message,
} from 'ant-design-vue';

import SensitiveText from '#/components/sensitive-text/SensitiveText.vue';
import {
  DEFAULT_SUB_WINDOW_Z_INDEX,
  getSubWindowPopupZIndex,
} from '#/components/sub-window/constants';
import SubWindow from '#/components/sub-window/SubWindow.vue';
import {
  getTransferPrescriptionListByStoreApi,
  updateTransferPrescriptionHandleStatusApi,
} from '#/views/business/salesperson-transfer-prescription/api';
import { invokeDoctorTransferImport } from '#/views/doctor/doctor-reception/composables/useDoctorReceptionTransferImport';

const REFRESH_STORAGE_KEY = 'pc_doctor_transfer_refresh_sec';
const DEFAULT_AVATAR = '/img/user-default-avatar.png';
const IMAGE_SCALE_MIN = 0.5;
const IMAGE_SCALE_MAX = 3;
const IMAGE_SCALE_STEP = 0.25;

const userStore = useUserStore();
const { isDark } = usePreferences();

/** 与子窗口 z-index 对齐的弹出层层级 */
const popupZIndex = computed(() => getSubWindowPopupZIndex(DEFAULT_SUB_WINDOW_Z_INDEX));

const windowOpen = ref(false);
const loading = ref(false);
const list = ref<any[]>([]);
const pollTimer = ref<ReturnType<typeof setInterval> | null>(null);
const inlineImageUrl = ref('');
const imageScale = ref(1);
const imagePanX = ref(0);
const imagePanY = ref(0);
const imageDragging = ref(false);
const imageDragStartX = ref(0);
const imageDragStartY = ref(0);
const imagePanOriginX = ref(0);
const imagePanOriginY = ref(0);

const salespersonKeyword = ref('');
const patientName = ref('');
const refreshIntervalSec = ref(30);

const exceptionModalOpen = ref(false);
const exceptionMessage = ref('');
const pendingStatusItem = ref<any>(null);

const storeId = computed(() => Number(userStore.userInfo?.store_id || 0));

const pendingCount = computed(
  () => list.value.filter((item) => Number(item.status) === 0).length,
);

const refreshOptions = [
  { value: 0, label: '不刷新' },
  { value: 10, label: '10秒' },
  { value: 30, label: '30秒' },
  { value: 60, label: '1分钟' },
];

const statusOptions = [
  { value: 0, label: '未处理' },
  { value: 1, label: '处理中' },
  { value: 2, label: '已完成' },
  { value: 3, label: '异常' },
];

const imageTransformStyle = computed(() => ({
  transform: `translate(${imagePanX.value}px, ${imagePanY.value}px) scale(${imageScale.value})`,
  transformOrigin: 'center top',
}));

/** Dropdown 挂载到 body，避免被 overflow 裁剪 */
function getPopupContainer() {
  return document.body;
}

function statusColor(status: number) {
  const map: Record<number, string> = {
    0: 'warning',
    1: 'processing',
    2: 'success',
    3: 'error',
  };
  return map[Number(status)] || 'default';
}

/** 重置内嵌看图缩放与平移 */
function resetImageView() {
  imageScale.value = 1;
  imagePanX.value = 0;
  imagePanY.value = 0;
}

/** 从 localStorage 读取刷新间隔配置 */
function loadRefreshSetting() {
  const cached = localStorage.getItem(REFRESH_STORAGE_KEY);
  if (cached !== null) {
    const val = Number(cached);
    if ([0, 10, 30, 60].includes(val)) {
      refreshIntervalSec.value = val;
    }
  }
}

function saveRefreshSetting() {
  localStorage.setItem(REFRESH_STORAGE_KEY, String(refreshIntervalSec.value));
}

/** 加载当前门店传方列表 */
async function loadList(silent = false) {
  if (!storeId.value) return;
  if (!silent) loading.value = true;
  try {
    const params: Record<string, any> = {
      store_id: storeId.value,
      page: 1,
      pageSize: 50,
    };
    if (salespersonKeyword.value.trim()) {
      params.salesperson_keyword = salespersonKeyword.value.trim();
    }
    if (patientName.value.trim()) {
      params.patient_name = patientName.value.trim();
    }
    const res = await getTransferPrescriptionListByStoreApi(params);
    list.value = res?.items ?? [];
  } catch (e) {
    console.error(e);
    if (!silent) list.value = [];
  } finally {
    loading.value = false;
  }
}

function handleSearch() {
  loadList();
}

function handleManualRefresh() {
  loadList();
}

/** 按配置间隔启动轮询（0 表示不自动刷新） */
function restartPoll() {
  stopPoll();
  const sec = refreshIntervalSec.value;
  if (sec <= 0) return;
  pollTimer.value = setInterval(() => loadList(true), sec * 1000);
}

function stopPoll() {
  if (pollTimer.value) {
    clearInterval(pollTimer.value);
    pollTimer.value = null;
  }
}

function openWindow() {
  windowOpen.value = true;
  inlineImageUrl.value = '';
  resetImageView();
  loadList();
}

function openImageInWindow(url: string) {
  inlineImageUrl.value = url;
  resetImageView();
}

function closeInlineImage() {
  inlineImageUrl.value = '';
  resetImageView();
}

function zoomIn() {
  imageScale.value = Math.min(
    IMAGE_SCALE_MAX,
    Math.round((imageScale.value + IMAGE_SCALE_STEP) * 100) / 100,
  );
}

function zoomOut() {
  imageScale.value = Math.max(
    IMAGE_SCALE_MIN,
    Math.round((imageScale.value - IMAGE_SCALE_STEP) * 100) / 100,
  );
}

function resetImageZoom() {
  resetImageView();
}

/** 滚轮缩放图片 */
function onImageWheel(e: WheelEvent) {
  e.preventDefault();
  if (e.deltaY < 0) zoomIn();
  else zoomOut();
}

/** 内嵌看图：按住拖拽平移 */
function onImageMouseDown(e: MouseEvent) {
  if (e.button !== 0) return;
  imageDragging.value = true;
  imageDragStartX.value = e.clientX;
  imageDragStartY.value = e.clientY;
  imagePanOriginX.value = imagePanX.value;
  imagePanOriginY.value = imagePanY.value;
  document.addEventListener('mousemove', onImageMouseMove);
  document.addEventListener('mouseup', onImageMouseUp);
}

function onImageMouseMove(e: MouseEvent) {
  if (!imageDragging.value) return;
  imagePanX.value = imagePanOriginX.value + (e.clientX - imageDragStartX.value);
  imagePanY.value = imagePanOriginY.value + (e.clientY - imageDragStartY.value);
}

function onImageMouseUp() {
  imageDragging.value = false;
  document.removeEventListener('mousemove', onImageMouseMove);
  document.removeEventListener('mouseup', onImageMouseUp);
}

/** 选择处理状态 */
async function handleStatusSelect(item: any, status: number) {
  if (status === 3) {
    pendingStatusItem.value = item;
    exceptionMessage.value = item.exception_message || '';
    exceptionModalOpen.value = true;
    return;
  }
  await submitStatus(item, status, '');
}

async function submitStatus(item: any, status: number, exceptionMsg: string) {
  if (!storeId.value) return;
  try {
    await updateTransferPrescriptionHandleStatusApi({
      id: item.id,
      store_id: storeId.value,
      status,
      exception_message: status === 3 ? exceptionMsg : '',
    });
    message.success('状态已更新');
    exceptionModalOpen.value = false;
    pendingStatusItem.value = null;
    loadList(true);
  } catch (e: any) {
    message.error(e?.message || '更新失败');
  }
}

async function confirmException() {
  if (!exceptionMessage.value.trim()) {
    message.warning('请填写异常说明');
    return;
  }
  if (pendingStatusItem.value) {
    await submitStatus(pendingStatusItem.value, 3, exceptionMessage.value.trim());
  }
}

/** 是否可导入：手动输入且有药品 */
function canImportItem(item: any) {
  if (Number(item.transfer_mode ?? 1) === 2) return false;
  return Boolean(item.drug_list?.length || item.drug_text_lines?.length);
}

/** 当前接诊页选中的挂号 ID */
function getCurrentRegisterId() {
  return Number.parseInt(localStorage.getItem('doctorReception-id') || '0', 10);
}

/** 导入传方药品到当前接诊患者 */
function handleImportToCurrentPatient(item: any) {
  const registerId = getCurrentRegisterId();
  if (!registerId) {
    message.warning('请先在接诊页选择患者');
    return;
  }
  if (!canImportItem(item)) {
    message.warning('仅支持手动输入药品的传方');
    return;
  }
  const ok = invokeDoctorTransferImport({ transferId: item.id, registerId });
  if (!ok) {
    message.warning('请先打开接诊页面');
  }
}

watch(refreshIntervalSec, () => {
  saveRefreshSetting();
  restartPoll();
});

watch(windowOpen, (v) => {
  if (!v) {
    inlineImageUrl.value = '';
    resetImageView();
  }
});

watch(storeId, () => {
  if (windowOpen.value) loadList(true);
});

onBeforeUnmount(() => {
  stopPoll();
  document.removeEventListener('mousemove', onImageMouseMove);
  document.removeEventListener('mouseup', onImageMouseUp);
});

onMounted(() => {
  loadRefreshSetting();
  loadList(true);
  restartPoll();
});

defineExpose({ loadList });
</script>

<template>
  <div class="doctor-transfer-header-entry">
    <Tooltip title="门店传方">
      <Badge :count="pendingCount" :overflow-count="99" size="small">
        <Button
          type="text"
          class="transfer-header-btn"
          @click="openWindow"
        >
          <FileTextOutlined />
          <span class="transfer-header-btn__text">传方</span>
        </Button>
      </Badge>
    </Tooltip>
  </div>
  <SubWindow
    v-model:open="windowOpen"
    title="门店传方"
    storage-key="pc_doctor_transfer_window"
    :width="440"
    :height="560"
    :min-width="360"
    :min-height="320"
    :z-index="DEFAULT_SUB_WINDOW_Z_INDEX"
  >
    <div class="panel" :class="{ 'is-dark': isDark }">
      <div v-if="inlineImageUrl" class="inline-image-layer">
        <div class="inline-image-toolbar">
          <Button type="link" size="small" @click="closeInlineImage">返回列表</Button>
          <Button type="link" size="small" @click="zoomIn">
            <ZoomInOutlined /> 放大
          </Button>
          <Button type="link" size="small" @click="zoomOut">
            <ZoomOutOutlined /> 缩小
          </Button>
          <Button type="link" size="small" @click="resetImageZoom">还原</Button>
          <span class="zoom-percent">{{ Math.round(imageScale * 100) }}%</span>
        </div>
        <div
          class="inline-image-body"
          :class="{ dragging: imageDragging }"
          @wheel="onImageWheel"
          @mousedown="onImageMouseDown"
        >
          <img
            :src="inlineImageUrl"
            class="inline-image"
            :style="imageTransformStyle"
            alt="处方图"
            draggable="false"
          />
        </div>
      </div>

      <div class="toolbar">
        <div class="toolbar-row">
          <Input.Search
            v-model:value="salespersonKeyword"
            allow-clear
            placeholder="推广员姓名/手机"
            size="small"
            class="toolbar-input"
            @search="handleSearch"
          />
          <Input.Search
            v-model:value="patientName"
            allow-clear
            placeholder="收货人姓名"
            size="small"
            class="toolbar-input"
            @search="handleSearch"
          />
        </div>
        <div class="toolbar-row toolbar-row-bottom">
          <span class="toolbar-label">刷新</span>
          <Select
            v-model:value="refreshIntervalSec"
            size="small"
            class="toolbar-select"
            :options="refreshOptions"
            :get-popup-container="getPopupContainer"
            :dropdown-style="{ zIndex: popupZIndex }"
          />
          <Button size="small" :loading="loading" @click="handleManualRefresh">
            <ReloadOutlined />
          </Button>
        </div>
      </div>

      <div class="panel-body">
        <div class="panel-scroll">
          <Spin :spinning="loading">
            <div v-if="!loading && !list.length" class="empty-tip">暂无传方记录</div>
            <div v-for="item in list" :key="item.id" class="transfer-card">
            <div class="card-head">
              <span class="store-name">{{ item.store_name || '—' }}</span>
              <Tag :color="statusColor(item.status)">
                {{ item.status_text || '未处理' }}
              </Tag>
            </div>
            <div class="salesperson-row">
              <Image
                :src="item.salesperson_avatar || DEFAULT_AVATAR"
                :width="32"
                :height="32"
                class="salesperson-avatar"
                :preview="false"
              />
              <div class="salesperson-info">
                <div class="salesperson-name">{{ item.salesperson_name || '—' }}</div>
                <div v-if="item.salesperson_phone" class="salesperson-phone">
                  {{ item.salesperson_phone }}
                </div>
              </div>
            </div>
            <div class="card-row">
              <span class="label">收货人</span>
              <span class="value">
                {{ item.patient_name }}
                <SensitiveText :record="item" field="patient_mobile" :show-eye="false" />
              </span>
            </div>
            <div v-if="item.patient_address" class="card-row">
              <span class="label">地址</span>
              <span class="value ellipsis">{{ item.patient_address }}</span>
            </div>
            <div v-if="item.remark" class="card-row">
              <span class="label">备注</span>
              <span class="value">{{ item.remark }}</span>
            </div>
            <div
              v-if="item.drug_text_lines?.length"
              class="drug-block drug-block--importable"
              @click="canImportItem(item) && handleImportToCurrentPatient(item)"
            >
              <span class="label">药方</span>
              <div class="drug-lines">
                <div
                  v-for="(line, idx) in item.drug_text_lines"
                  :key="'d-' + idx"
                  class="drug-line"
                >
                  {{ line }}
                </div>
              </div>
              <span v-if="canImportItem(item)" class="import-hint">点击导入到当前患者</span>
            </div>
            <div v-if="item.prescription_images?.length" class="img-block">
              <span class="label">处方图</span>
              <div class="img-row">
                <Image
                  v-for="(img, idx) in item.prescription_images"
                  :key="'img-' + idx"
                  :src="img"
                  :width="64"
                  :height="64"
                  class="thumb"
                  :preview="{ zIndex: popupZIndex }"
                />
              </div>
              <Button
                type="link"
                size="small"
                class="link-btn"
                @click="openImageInWindow(item.prescription_images[0])"
              >
                在窗口查看
              </Button>
            </div>
            <div
              v-if="item.status === 3 && item.exception_message"
              class="exception-box"
            >
              异常：{{ item.exception_message }}
            </div>
            <div class="card-foot">
              <span class="time">{{ item.transfer_time_text }}</span>
              <div class="card-foot-actions">
                <Button
                  v-if="canImportItem(item)"
                  size="small"
                  type="primary"
                  @click="handleImportToCurrentPatient(item)"
                >
                  导入到当前患者
                </Button>
                <Dropdown
                  :trigger="['click']"
                  :get-popup-container="getPopupContainer"
                  :overlay-style="{ zIndex: popupZIndex }"
                >
                  <Button size="small" type="primary" ghost>操作</Button>
                  <template #overlay>
                    <Menu @click="({ key }) => handleStatusSelect(item, Number(key))">
                      <Menu.Item v-for="opt in statusOptions" :key="String(opt.value)">
                        {{ opt.label }}
                      </Menu.Item>
                    </Menu>
                  </template>
                </Dropdown>
              </div>
            </div>
            </div>
          </Spin>
        </div>
      </div>
    </div>
  </SubWindow>
  <Modal
    v-model:open="exceptionModalOpen"
    title="填写异常说明"
    ok-text="确认"
    cancel-text="取消"
    :z-index="popupZIndex"
    @ok="confirmException"
  >
    <Textarea
      v-model:value="exceptionMessage"
      :rows="4"
      placeholder="请描述异常原因"
    />
  </Modal>
</template>

<style scoped>
.panel {
  flex: 1;
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.toolbar {
  flex-shrink: 0;
  padding: 12px;
  border-bottom: 1px solid #eee;
}
.panel.is-dark .toolbar {
  border-bottom-color: #424242;
}
.toolbar-row {
  display: flex;
  gap: 8px;
}
.toolbar-row-bottom {
  margin-top: 8px;
  align-items: center;
}
.toolbar-input {
  flex: 1;
}
.toolbar-select {
  flex: 1;
}
.toolbar-label {
  flex-shrink: 0;
  font-size: 12px;
  color: #86909c;
}
.panel.is-dark .toolbar-label {
  color: rgba(255, 255, 255, 0.45);
}
/* 内部滚动：panel-body 限定高度，panel-scroll 为唯一滚动容器 */
.panel-body {
  flex: 1 1 0;
  min-height: 0;
  overflow: hidden;
}
.panel-scroll {
  height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 12px;
}
.empty-tip {
  text-align: center;
  color: #999;
  padding: 40px 0;
}
.panel.is-dark .empty-tip {
  color: rgba(255, 255, 255, 0.45);
}
.transfer-card {
  background: #f9fafb;
  border-radius: 8px;
  padding: 12px;
  margin-bottom: 12px;
  border: 1px solid #eee;
}
.panel.is-dark .transfer-card {
  background: #262626;
  border-color: #424242;
}
.card-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
}
.store-name {
  font-weight: 600;
  font-size: 14px;
  color: #1d2129;
}
.panel.is-dark .store-name {
  color: rgba(255, 255, 255, 0.85);
}
.salesperson-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}
.salesperson-avatar {
  flex-shrink: 0;
  border-radius: 50%;
  object-fit: cover;
}
.salesperson-info {
  min-width: 0;
  flex: 1;
}
.salesperson-name {
  font-size: 14px;
  font-weight: 500;
  color: #1d2129;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.panel.is-dark .salesperson-name {
  color: rgba(255, 255, 255, 0.85);
}
.salesperson-phone {
  font-size: 12px;
  color: #86909c;
}
.panel.is-dark .salesperson-phone {
  color: rgba(255, 255, 255, 0.45);
}
.card-row {
  display: flex;
  font-size: 13px;
  margin-bottom: 6px;
  line-height: 1.5;
}
.label {
  color: #86909c;
  width: 56px;
  flex-shrink: 0;
}
.panel.is-dark .label {
  color: rgba(255, 255, 255, 0.45);
}
.value {
  color: #4e5969;
  flex: 1;
}
.panel.is-dark .value {
  color: rgba(255, 255, 255, 0.65);
}
.ellipsis {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.drug-block {
  margin: 6px 0;
  display: flex;
  font-size: 13px;
}
.drug-block--importable {
  flex-wrap: wrap;
  cursor: pointer;
  padding: 6px 8px;
  border-radius: 4px;
  transition: background 0.15s;
}
.drug-block--importable:hover {
  background: rgba(0, 135, 113, 0.08);
}
.panel.is-dark .drug-block--importable:hover {
  background: rgba(52, 211, 153, 0.12);
}
.import-hint {
  flex-basis: 100%;
  font-size: 12px;
  color: #008771;
  margin-top: 4px;
  margin-left: 56px;
}
.panel.is-dark .import-hint {
  color: #34d399;
}
.drug-lines {
  flex: 1;
}
.drug-line {
  color: #008771;
  margin-bottom: 2px;
}
.panel.is-dark .drug-line {
  color: #34d399;
}
.img-block {
  margin-top: 6px;
}
.img-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 6px 0 6px 56px;
}
.thumb {
  object-fit: cover;
  border-radius: 4px;
}
.link-btn {
  padding-left: 56px;
}
.exception-box {
  background: #fef2f2;
  color: #991b1b;
  font-size: 12px;
  padding: 8px;
  border-radius: 4px;
  margin-top: 6px;
}
.panel.is-dark .exception-box {
  background: rgba(127, 29, 29, 0.35);
  color: #fca5a5;
}
.card-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed #e5e7eb;
}
.card-foot-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}
.panel.is-dark .card-foot {
  border-top-color: #424242;
}
.time {
  font-size: 12px;
  color: #999;
}
.panel.is-dark .time {
  color: rgba(255, 255, 255, 0.45);
}
.inline-image-layer {
  position: absolute;
  inset: 0;
  background: #fff;
  z-index: 10;
  display: flex;
  flex-direction: column;
}
.panel.is-dark .inline-image-layer {
  background: #1f1f1f;
}
.inline-image-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-bottom: 1px solid #eee;
  flex-shrink: 0;
}
.panel.is-dark .inline-image-toolbar {
  border-bottom-color: #424242;
}
.zoom-percent {
  font-size: 12px;
  color: #86909c;
}
.panel.is-dark .zoom-percent {
  color: rgba(255, 255, 255, 0.45);
}
.inline-image-body {
  flex: 1;
  overflow: auto;
  overscroll-behavior: contain;
  padding: 12px;
  cursor: grab;
}
.inline-image-body.dragging {
  cursor: grabbing;
}
.inline-image {
  width: 100%;
  height: auto;
  display: block;
  margin: 0 auto;
  user-select: none;
}
.doctor-transfer-header-entry {
  display: flex;
  align-items: center;
  margin-right: 4px;
}
.transfer-header-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 32px;
  padding: 0 8px;
  color: hsl(var(--foreground));
}
.transfer-header-btn__text {
  font-size: 13px;
}
@media (max-width: 640px) {
  .transfer-header-btn__text {
    display: none;
  }
}
</style>
