<script lang="ts" setup>
import { onMounted, ref } from 'vue';

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

import { Button, Card, Checkbox, Input, InputNumber, message, Radio, Space, Switch, Tabs, Tag } from 'ant-design-vue';

import type { QuickDiscountOption } from '#/utils/pricePercentAdjust';

import FormAvatar from '#/components/form/components/avatar.vue';

import AiModelConfigPanel from './components/ai-model-config-panel.vue';
import OaNotifyConfigPanel from './components/oa-notify-config-panel.vue';
import { getSystemConfigList, saveSystemConfig } from './api';

defineOptions({ name: 'SystemConfig' });

const TAB_STORAGE_KEY = 'system_config_active_tab';

const loading = ref(false);
const saving = ref(false);
const activeKey = ref('price_adjust');
const scope = ref<'both' | 'sale_only'>('sale_only');
const quickOptions = ref<QuickDiscountOption[]>([
  { name: '九五折', value: 95 },
  { name: '九折', value: 90 },
  { name: '八五折', value: 85 },
  { name: '八折', value: 80 },
  { name: '涨10%', value: 110 },
  { name: '涨20%', value: 120 },
]);
const newQuickName = ref('');
const newQuickValue = ref<number | null>(null);
const inputAutoAuditPass = ref(true);
const miniprogramEmptyImage = ref('');
/** 患者端物流是否显示配送仓名（默认否） */
const logisticsShowWhNameUser = ref(false);
/** 诊所端物流是否显示配送仓名（默认是） */
const logisticsShowWhNameClinic = ref(true);
/** 业务员是否允许编辑/改价/配置所属诊所（默认否） */
const salespersonStoreEditEnabled = ref(false);
/** 业务端单机登录：医生/药师/诊所管理员等同一账号仅 1 手机 + 1 网页（默认否） */
const doctorSingleDeviceLogin = ref(false);
/** 字典搜索匹配度：backend 服务端 / frontend 前端 */
const dictSearchRankMode = ref<'backend' | 'frontend'>('backend');
/**
 * 病历诊断/医嘱「常用|我的」展示位置
 * tags=文本域下标签（默认） bubble=气泡内展示 both=两边
 */
const mrCommonDisplayMode = ref<'tags' | 'bubble' | 'both'>('tags');
/** 开票通知渠道：subscribe / sms，默认仅订阅消息 */
const invoiceNoticeChannels = ref<string[]>(['subscribe']);

function readStoredTab() {
  const stored = localStorage.getItem(TAB_STORAGE_KEY);
  if (
    stored === 'price_adjust' ||
    stored === 'input_audit' ||
    stored === 'miniprogram' ||
    stored === 'logistics' ||
    stored === 'salesperson' ||
    stored === 'invoice_notice' ||
    stored === 'doctor_login' ||
    stored === 'dict_search' ||
    stored === 'medical_record' ||
    stored === 'oa_notify' ||
    stored === 'ai_model'
  ) {
    activeKey.value = stored;
  }
}

function parseBoolConfig(val: unknown, defaultVal: boolean): boolean {
  if (val === undefined || val === null || val === '') return defaultVal;
  return val === '1' || val === 1 || val === true || val === 'true';
}

function handleTabChange(key: string | number) {
  activeKey.value = String(key);
  localStorage.setItem(TAB_STORAGE_KEY, String(key));
}

function parseQuickOptions(raw: unknown): QuickDiscountOption[] {
  if (typeof raw === 'string') {
    try {
      const parsed = JSON.parse(raw);
      return parseQuickOptions(parsed);
    } catch {
      return quickOptions.value;
    }
  }
  if (!Array.isArray(raw)) return quickOptions.value;
  const list: QuickDiscountOption[] = [];
  for (const item of raw) {
    if (item && typeof item === 'object' && 'value' in item) {
      const val = Number((item as QuickDiscountOption).value);
      if (val > 0) list.push({ name: String((item as QuickDiscountOption).name || `${val}%`), value: val });
    } else if (typeof item === 'number' && item > 0) {
      list.push({ name: `${item}%`, value: item });
    }
  }
  return list.length ? list : quickOptions.value;
}

async function load() {
  loading.value = true;
  try {
    const list = await getSystemConfigList();
    const rows = Array.isArray(list) ? list : list?.data || [];
    for (const row of rows) {
      if (row.config_key === 'order_price_adjust_scope') {
        scope.value = row.config_value === 'both' ? 'both' : 'sale_only';
      }
      if (row.config_key === 'order_discount_quick_options') {
        quickOptions.value = parseQuickOptions(row.config_value);
      }
      if (row.config_key === 'input_auto_audit_pass') {
        inputAutoAuditPass.value = row.config_value === '1' || row.config_value === true || row.config_value === 'true';
      }
      if (row.config_key === 'miniprogram_empty_image') {
        miniprogramEmptyImage.value = String(row.config_value || '');
      }
      if (row.config_key === 'logistics_show_warehouse_name_user') {
        logisticsShowWhNameUser.value = parseBoolConfig(row.config_value, false);
      }
      if (row.config_key === 'logistics_show_warehouse_name_clinic') {
        logisticsShowWhNameClinic.value = parseBoolConfig(row.config_value, true);
      }
      if (row.config_key === 'salesperson_store_edit_enabled') {
        salespersonStoreEditEnabled.value = parseBoolConfig(row.config_value, false);
      }
      if (row.config_key === 'doctor_single_device_login') {
        doctorSingleDeviceLogin.value = parseBoolConfig(row.config_value, false);
      }
      if (row.config_key === 'dict_search_rank_mode') {
        dictSearchRankMode.value =
          String(row.config_value || '') === 'frontend' ? 'frontend' : 'backend';
      }
      if (row.config_key === 'mr_common_display_mode') {
        const mode = String(row.config_value || 'tags');
        mrCommonDisplayMode.value =
          mode === 'bubble' || mode === 'both' ? mode : 'tags';
      }
      if (row.config_key === 'invoice_notice_channels') {
        let channels: unknown = row.config_value;
        if (typeof channels === 'string') {
          try {
            channels = JSON.parse(channels);
          } catch {
            channels = ['subscribe'];
          }
        }
        if (Array.isArray(channels) && channels.length) {
          invoiceNoticeChannels.value = channels.map(String).filter((c) => c === 'subscribe' || c === 'sms');
        }
        if (!invoiceNoticeChannels.value.length) {
          invoiceNoticeChannels.value = ['subscribe'];
        }
      }
    }
  } finally {
    loading.value = false;
  }
}

function addQuick() {
  const v = Number(newQuickValue.value);
  const name = String(newQuickName.value || '').trim();
  if (!name || !v || v <= 0) {
    message.warning('请填写名称和有效比例值');
    return;
  }
  if (!quickOptions.value.some((o) => o.value === v && o.name === name)) {
    quickOptions.value = [...quickOptions.value, { name, value: v }].sort((a, b) => b.value - a.value);
  }
  newQuickName.value = '';
  newQuickValue.value = null;
}

function removeQuick(opt: QuickDiscountOption) {
  quickOptions.value = quickOptions.value.filter((o) => !(o.name === opt.name && o.value === opt.value));
}

async function handleSave() {
  saving.value = true;
  try {
    await saveSystemConfig([
      { config_key: 'order_price_adjust_scope', config_value: scope.value },
      {
        config_key: 'order_discount_quick_options',
        config_value: JSON.stringify(quickOptions.value),
      },
      {
        config_key: 'input_auto_audit_pass',
        config_value: inputAutoAuditPass.value ? '1' : '0',
      },
      {
        config_key: 'miniprogram_empty_image',
        config_value: miniprogramEmptyImage.value,
      },
      {
        config_key: 'logistics_show_warehouse_name_user',
        config_value: logisticsShowWhNameUser.value ? '1' : '0',
      },
      {
        config_key: 'logistics_show_warehouse_name_clinic',
        config_value: logisticsShowWhNameClinic.value ? '1' : '0',
      },
      {
        config_key: 'salesperson_store_edit_enabled',
        config_value: salespersonStoreEditEnabled.value ? '1' : '0',
        value_type: 'bool',
        config_group: 'salesperson',
        description: '允许业务员编辑/改价/配置所属诊所',
        sort: 300,
      },
      {
        config_key: 'doctor_single_device_login',
        config_value: doctorSingleDeviceLogin.value ? '1' : '0',
        value_type: 'bool',
        config_group: 'auth',
        description: '业务端单机登录（医生/药师/诊所管理员等：1手机+1网页）',
        sort: 310,
      },
      {
        config_key: 'dict_search_rank_mode',
        config_value: dictSearchRankMode.value,
        value_type: 'string',
        config_group: 'search',
        description: '字典搜索匹配度：backend服务端 / frontend前端',
        sort: 320,
      },
      {
        config_key: 'mr_common_display_mode',
        config_value: mrCommonDisplayMode.value,
        value_type: 'string',
        config_group: 'medical_record',
        description: '病历诊断医嘱常用展示：tags标签 / bubble气泡 / both两边',
        sort: 330,
      },
      {
        config_key: 'invoice_notice_channels',
        config_value: JSON.stringify(
          invoiceNoticeChannels.value.length ? invoiceNoticeChannels.value : ['subscribe'],
        ),
        value_type: 'json',
        config_group: 'invoice',
        description: '开票通知渠道：subscribe订阅消息 / sms短信',
        sort: 200,
      },
    ]);
    message.success('保存成功');
  } finally {
    saving.value = false;
  }
}

onMounted(() => {
  readStoredTab();
  load();
});
</script>

<template>
  <Page auto-content-height title="系统配置">
    <Card :loading="loading">
      <Tabs :active-key="activeKey" @change="handleTabChange">
        <Tabs.TabPane key="price_adjust" tab="订单调价">
          <div class="py-4">
            <div class="mb-6">
              <div class="mb-2 font-medium">订单打折时价格浮动范围</div>
              <Radio.Group v-model:value="scope">
                <Radio value="sale_only">仅售价浮动</Radio>
                <Radio value="both">供货价与售价一起浮动</Radio>
              </Radio.Group>
            </div>

            <div class="mb-6">
              <div class="mb-2 font-medium">调价快捷选项（name 展示名，value 比例：100=原价，90=九折，120=涨20%）</div>
              <Space wrap class="mb-3">
                <Tag
                  v-for="item in quickOptions"
                  :key="item.name + item.value"
                  closable
                  :color="item.value < 100 ? 'processing' : 'warning'"
                  @close="removeQuick(item)"
                >
                  {{ item.name }}（{{ item.value }}%）
                </Tag>
              </Space>
              <Space wrap>
                <Input v-model:value="newQuickName" placeholder="名称，如九折" style="width: 140px" />
                <InputNumber v-model:value="newQuickValue" :min="1" :max="500" placeholder="比例值" />
                <Button @click="addQuick">添加快捷项</Button>
              </Space>
            </div>
          </div>
        </Tabs.TabPane>

        <Tabs.TabPane key="input_audit" tab="录入审核">
          <div class="py-4">
            <div class="mb-2 font-medium">诊所/医生信息预填录入后是否自动通过审核</div>
            <Switch v-model:checked="inputAutoAuditPass" checked-children="是" un-checked-children="否" />
          </div>
        </Tabs.TabPane>

        <Tabs.TabPane key="miniprogram" tab="小程序">
          <div class="py-4">
            <div class="mb-2 font-medium">空状态图片</div>
            <div class="mb-2 text-sm text-gray-500">用于小程序列表等无数据时的占位图</div>
            <FormAvatar v-model:value="miniprogramEmptyImage" />
          </div>
        </Tabs.TabPane>

        <Tabs.TabPane key="logistics" tab="物流展示">
          <div class="py-4 space-y-6">
            <div>
              <div class="mb-2 font-medium">患者端：物流多包裹是否显示配送仓名称</div>
              <div class="mb-2 text-sm text-gray-500">
                关闭后患者端仅显示「包裹1」「包裹2」，不展示仓名
              </div>
              <Switch
                v-model:checked="logisticsShowWhNameUser"
                checked-children="显示"
                un-checked-children="隐藏"
              />
            </div>
            <div>
              <div class="mb-2 font-medium">诊所端：物流多包裹是否显示配送仓名称</div>
              <div class="mb-2 text-sm text-gray-500">
                关闭后诊所/商家小程序订单物流仅显示包裹序号；平台后台产品订单不受影响
              </div>
              <Switch
                v-model:checked="logisticsShowWhNameClinic"
                checked-children="显示"
                un-checked-children="隐藏"
              />
            </div>
          </div>
        </Tabs.TabPane>

        <Tabs.TabPane key="salesperson" tab="业务员权限">
          <div class="py-4">
            <div class="mb-2 font-medium">允许业务员编辑/改价/配置所属诊所</div>
            <div class="mb-2 text-sm text-gray-500">
              关闭时业务员小程序「我的诊所」仅可查看；开启后显示编辑资料、改价、配置开关等操作
            </div>
            <Switch
              v-model:checked="salespersonStoreEditEnabled"
              checked-children="开启"
              un-checked-children="关闭"
            />
          </div>
        </Tabs.TabPane>

        <Tabs.TabPane key="doctor_login" tab="登录安全">
          <div class="py-4">
            <div class="mb-2 font-medium">单机登录</div>
            <div class="mb-2 text-sm text-gray-500">
              适用于医生/药师/诊所管理员/平台管理员/业务员及 PC 管理端。关闭时不限制登录设备；开启后同一账号仅允许 1 个手机端会话 + 1 个 PC 网页会话，同端后登录会使先登录失效；同手机号下不同身份互不影响
            </div>
            <Switch
              v-model:checked="doctorSingleDeviceLogin"
              checked-children="开启"
              un-checked-children="关闭"
            />
          </div>
        </Tabs.TabPane>

        <Tabs.TabPane key="dict_search" tab="字典搜索">
          <div class="py-4">
            <div class="mb-2 font-medium">诊断 / 医嘱 / 病历词条匹配度处理端</div>
            <div class="mb-2 text-sm text-gray-500">
              后端：服务端计算匹配度并排序（适合疾病库等大数据量）；前端：接口只返回候选，由端上打分排序（适合调试或减轻服务端 CPU）。关键字高亮始终在端上渲染。
            </div>
            <Radio.Group v-model:value="dictSearchRankMode">
              <Radio value="backend">后端处理（推荐）</Radio>
              <Radio value="frontend">前端处理</Radio>
            </Radio.Group>
          </div>
        </Tabs.TabPane>

        <Tabs.TabPane key="medical_record" tab="词条">
          <div class="py-4">
            <div class="mb-2 font-medium">诊断 / 医嘱「常用|我的」展示位置</div>
            <div class="mb-2 text-sm text-gray-500">
              控制接诊病历里诊断、医嘱的常用快捷出现在哪里。默认「标签」即文本域下方的快捷标签；「气泡卡片」则在关键字搜索气泡内默认展示常用；「两边」同时展示。
            </div>
            <Radio.Group v-model:value="mrCommonDisplayMode">
              <Radio value="tags">标签（默认）</Radio>
              <Radio value="bubble">气泡卡片默认展示</Radio>
              <Radio value="both">两边都展示</Radio>
            </Radio.Group>
          </div>
        </Tabs.TabPane>

        <Tabs.TabPane key="invoice_notice" tab="开票通知">
          <div class="py-4">
            <div class="mb-2 font-medium">患者开票通知渠道</div>
            <div class="mb-2 text-sm text-gray-500">
              受理与开票完成时按所选渠道发送；可多选（全选）。默认仅小程序订阅消息。
            </div>
            <Checkbox.Group v-model:value="invoiceNoticeChannels">
              <Checkbox value="subscribe">小程序订阅消息</Checkbox>
              <Checkbox value="sms">短信</Checkbox>
            </Checkbox.Group>
          </div>
        </Tabs.TabPane>

        <Tabs.TabPane key="oa_notify" tab="OA通知">
          <OaNotifyConfigPanel />
        </Tabs.TabPane>

        <Tabs.TabPane key="ai_model" tab="AI模型">
          <AiModelConfigPanel />
        </Tabs.TabPane>
      </Tabs>

      <div v-if="activeKey !== 'oa_notify' && activeKey !== 'ai_model'" class="mt-4">
        <Button type="primary" :loading="saving" @click="handleSave">保存配置</Button>
      </div>
    </Card>
  </Page>
</template>
