const Base = require('../base.js');
const dayjs = require('dayjs');

const APP_REMARK = 'pap_mini_cytx';
const AUDIT_APPROVED_CONTENT = '您提交的肠愈同行患者关爱项目资料已审核通过，请于7天内在小程序-个人中心-送检信息中提交相关信息。';
const SAMPLE_EDIT_AUDIT_TEMPLATE_ID = 'OcMLIGS8pMnpGzZmPkdMELDgFefqOeQ-1jsit8Ldw2w';

module.exports = class extends Base {
  _canEditPatient() {
    return this.isSuperAdmin || (this.userPermissions || []).includes('patient:edit');
  }

  _adminOperator() {
    const user = this.adminUser || {};
    return {
      operator_id: user.id || 0,
      operator_name: user.nickname || user.username || ''
    };
  }

  _parseArrayValue(value) {
    if (Array.isArray(value)) return value;
    if (!value) return [];
    try { return JSON.parse(value || '[]') || []; } catch (e) { return []; }
  }

  _hasSampleInfo(patient = {}) {
    const sampleTypes = this._parseArrayValue(patient.sample_types);
    const samplePhotos = this._parseArrayValue(patient.sample_photos);
    return !!(
      sampleTypes.length ||
      samplePhotos.length ||
      patient.report_email ||
      patient.sample_tracking_no ||
      patient.return_name ||
      patient.return_phone ||
      patient.return_address
    );
  }

  _sampleInfoStatusText(patient = {}) {
    const status = Number(patient.sample_info_status) || 0;
    if (status === 3) return '修改申请待审核';
    if (status === 2) return '已寄回';
    if (status === 1) return '已生效';
    return this._hasSampleInfo(patient) ? '可修改' : '未提交';
  }

  _sampleInfoStatusType(patient = {}) {
    const status = Number(patient.sample_info_status) || 0;
    if (status === 3) return 'warning';
    if (status === 2) return 'primary';
    if (status === 1) return 'success';
    return this._hasSampleInfo(patient) ? 'warning' : 'info';
  }

  _buildFlowLogs(audits = [], sampleLogs = []) {
    const auditLogs = audits.map(item => {
      const action = item.action || '';
      let title = '资料流转';
      let content = '';
      if (action === 'submit') {
        title = '提交患者资料';
        content = `${item.operator_name || '系统'} 提交了患者资料，等待审核`;
      } else if (action === 'approve') {
        title = '患者资料审核通过';
        content = `${item.operator_name || '系统'} 审核通过`;
      } else if (action === 'reject') {
        title = '患者资料审核驳回';
        content = `${item.operator_name || '系统'} 驳回了资料`;
      }
      return {
        id: item.id,
        source: 'audit',
        action,
        title,
        content,
        reason: item.reason || '',
        operator_name: item.operator_name || '',
        operator_type: 'admin',
        create_time: item.create_time
      };
    });
    const logs = sampleLogs.map(item => ({
      id: item.id,
      source: 'sample',
      action: item.action || '',
      title: item.title || '送检信息',
      content: item.content || '',
      reason: item.reason || '',
      operator_name: item.operator_name || '',
      operator_type: item.operator_type || '',
      create_time: item.create_time
    }));
    return auditLogs.concat(logs).sort((a, b) => {
      const ta = new Date(a.create_time || 0).getTime();
      const tb = new Date(b.create_time || 0).getTime();
      if (tb !== ta) return tb - ta;
      return (b.id || 0) - (a.id || 0);
    });
  }

  async _addSampleLog(patientId, action, title, content, reason = '') {
    const operator = this._adminOperator();
    return this.model('patient_sample_log').addLog({
      patient_id: patientId,
      action,
      title,
      content,
      reason,
      operator_type: 'admin',
      operator_id: operator.operator_id,
      operator_name: operator.operator_name
    });
  }

  // 患者列表页面
  async indexAction() {
    this.assign('currentPage', 'patient');
    this.assign('pageTitle', '患者管理');
    this.assign('breadcrumb', [{ name: '患者管理' }]);
    this.assign('adminUser', this.adminUser || {});
    this.assign('canAdd', this.isSuperAdmin || (this.userPermissions || []).includes('patient:add'));
    this.assign('canEdit', this.isSuperAdmin || (this.userPermissions || []).includes('patient:edit'));
    this.assign('canExport', this.isSuperAdmin || (this.userPermissions || []).includes('patient:export'));
    this.assign('canAudit', this.isSuperAdmin || (this.userPermissions || []).includes('patient:audit'));
    this.assign('canView', this.isSuperAdmin || (this.userPermissions || []).includes('patient:view'));
    this.assign('canDelete', this.isSuperAdmin || (this.userPermissions || []).includes('patient:delete'));
    return this.display();
  }

  // 获取患者列表接口
  async listAction() {
    const { keyword, tag, status, startDate, endDate, province_code, city_code, district_code, page = 1, pageSize = 10 } = this.get();
    const model = this.model('patient');
    const list = await model.getList({ keyword, tag, status, startDate, endDate, province_code, city_code, district_code, page, pageSize });

    // 收集所有省市区 code 批量查询名称
    const allCodes = new Set();
    list.data.forEach(item => {
      if (item.province_code) allCodes.add(item.province_code);
      if (item.city_code) allCodes.add(item.city_code);
      if (item.district_code) allCodes.add(item.district_code);
    });
    const regionMap = {};
    if (allCodes.size) {
      const regions = await this.model('sys_region')
        .where({ code: ['in', [...allCodes]] })
        .select();
      regions.forEach(r => { regionMap[r.code] = r.name; });
    }

    // 脱敏 + 拼接地区
    list.data.forEach(item => {
      if (item.id_card && item.id_card.length === 18) {
        item.id_card_mask = item.id_card.slice(0, 3) + '***********' + item.id_card.slice(-4);
      } else {
        item.id_card_mask = item.id_card || '';
      }
      if (item.phone && item.phone.length === 11) {
        item.phone_mask = item.phone.slice(0, 3) + '****' + item.phone.slice(-4);
      } else {
        item.phone_mask = item.phone || '';
      }
      const pName = regionMap[item.province_code] || '';
      const cName = regionMap[item.city_code] || '';
      const dName = regionMap[item.district_code] || '';
      item.region_name = [pName, cName, dName].filter(Boolean).join(' ');
      item.sample_info_status_text = this._sampleInfoStatusText(item);
      item.sample_info_status_type = this._sampleInfoStatusType(item);
    });

    const counts = await model.getStatusCounts({ keyword, tag, startDate, endDate, province_code, city_code, district_code });
    return this.success({ ...list, counts });
  }

  // 患者详情页面
  async detailAction() {
    const { id } = this.get();
    if (!id) return this.redirect('/admin/patient.html');

    this.assign('currentPage', 'patient');
    this.assign('pageTitle', '患者详情');
    this.assign('breadcrumb', [
      { name: '患者管理', url: '/admin/patient.html' },
      { name: '患者详情' }
    ]);
    this.assign('patientId', id);
    this.assign('adminUser', this.adminUser || {});
    this.assign('canAudit', this.isSuperAdmin || (this.userPermissions || []).includes('patient:audit'));
    this.assign('canEdit', this._canEditPatient());
    return this.display();
  }

  // 获取患者详情接口（不脱敏）
  async infoAction() {
    const { id } = this.get();
    if (!id) return this.fail('参数错误');

    const patient = await this.model('patient')
      .where({ id, is_deleted: 0 })
      .find();

    if (think.isEmpty(patient)) {
      return this.fail('患者不存在');
    }

    // 解析 JSON 字段
    try { patient.documents = JSON.parse(patient.documents || '[]'); } catch (e) { patient.documents = []; }
    try { patient.sample_types = JSON.parse(patient.sample_types || '[]'); } catch (e) { patient.sample_types = []; }
    try { patient.sample_photos = JSON.parse(patient.sample_photos || '[]'); } catch (e) { patient.sample_photos = []; }

    // 查询省市区名称（包含寄回地址）
    const allCodes = [
      patient.province_code, patient.city_code, patient.district_code,
      patient.return_province_code, patient.return_city_code, patient.return_district_code,
      patient.hospital_province_code, patient.hospital_city_code, patient.hospital_district_code
    ].filter(Boolean);
    if (allCodes.length) {
      const regions = await this.model('sys_region')
        .where({ code: ['in', allCodes] })
        .select();
      const regionMap = {};
      regions.forEach(r => { regionMap[r.code] = r.name; });
      patient.province_name = regionMap[patient.province_code] || '';
      patient.city_name = regionMap[patient.city_code] || '';
      patient.district_name = regionMap[patient.district_code] || '';
      patient.return_province_name = regionMap[patient.return_province_code] || '';
      patient.return_city_name = regionMap[patient.return_city_code] || '';
      patient.return_district_name = regionMap[patient.return_district_code] || '';
      patient.hospital_province_name = regionMap[patient.hospital_province_code] || '';
      patient.hospital_city_name = regionMap[patient.hospital_city_code] || '';
      patient.hospital_district_name = regionMap[patient.hospital_district_code] || '';
    }

    patient.sample_info_status_text = this._sampleInfoStatusText(patient);
    patient.sample_info_status_type = this._sampleInfoStatusType(patient);

    // 获取审核记录和送检流转日志
    const audits = await this.model('patient_audit')
      .where({ patient_id: id })
      .order('id DESC')
      .select();
    const sampleLogs = await this.model('patient_sample_log')
      .where({ patient_id: id })
      .order('id DESC')
      .select();
    const flowLogs = this._buildFlowLogs(audits, sampleLogs);

    return this.success({ patient, audits: flowLogs, flowLogs });
  }

  async sampleReceiverConfigAction() {
    const config = await this.model('sys_config').getSampleReceiverInfo();
    return this.success(config);
  }

  async saveSampleReceiverConfigAction() {
    if (!this._canEditPatient()) return this.fail('暂无权限');
    const { address, receiver, phone, contact_phone } = this.post();
    if (!address || !address.trim()) return this.fail('请填写收件地址');
    if (!receiver || !receiver.trim()) return this.fail('请填写收件人');
    if (!phone || !phone.trim()) return this.fail('请填写电话');

    await this.model('sys_config').setSampleReceiverInfo({ address, receiver, phone, contact_phone });
    await this.log('edit', '患者管理', '编辑送检信息配置');

    const config = await this.model('sys_config').getSampleReceiverInfo();
    return this.success(config);
  }

  // 新增患者
  async addAction() {
    const data = this.post();
    const { name, phone, id_card, gender, birth_date, province_code, city_code, district_code, address, hospital, hospital_province_code, hospital_city_code, hospital_district_code, emergency_contact, emergency_phone, tag, documents, sample_types, wax_return, return_name, return_phone, return_province_code, return_city_code, return_district_code, return_address, report_email, sample_tracking_no, sample_photos, sign_income, sign_privacy, sign_promise, sign_privacy_jhr, income_amount, guardian_name, guardian_id_card, guardian_relation } = data;

    if (!name || !phone || !id_card || !gender || !birth_date) {
      return this.fail('请填写完整信息');
    }

    if (!province_code || !city_code || !district_code) {
      return this.fail('请选择省市区');
    }

    if (!address) {
      return this.fail('请填写详细地址');
    }

    if (!/^1\d{10}$/.test(phone)) {
      return this.fail('手机号格式不正确');
    }

    if (!/^\d{17}[\dXx]$/.test(id_card)) {
      return this.fail('身份证号格式不正确');
    }

    const model = this.model('patient');

    // 唯一性校验
    const existByIdCardAndPhone = await model.where({ id_card, phone, is_deleted: 0 }).find();
    if (!think.isEmpty(existByIdCardAndPhone)) {
      return this.fail('该患者已存在（身份证+手机号匹配）');
    }
    const existByPhone = await model.where({ phone, is_deleted: 0 }).find();
    if (!think.isEmpty(existByPhone)) {
      return this.fail('该手机号已被其他患者使用');
    }
    const existByIdCard = await model.where({ id_card, is_deleted: 0 }).find();
    if (!think.isEmpty(existByIdCard)) {
      return this.fail('该身份证号已被其他患者使用');
    }

    const patientNo = model.generatePatientNo();

    const id = await model.add({
      patient_no: patientNo,
      name,
      phone,
      id_card,
      gender,
      birth_date,
      province_code: province_code || '',
      city_code: city_code || '',
      district_code: district_code || '',
      address: address || '',
      hospital: hospital || '',
      hospital_province_code: hospital_province_code || '',
      hospital_city_code: hospital_city_code || '',
      hospital_district_code: hospital_district_code || '',
      emergency_contact: emergency_contact || '',
      emergency_phone: emergency_phone || '',
      tag: tag || '',
      documents: JSON.stringify(documents || []),
      sample_types: JSON.stringify(sample_types || []),
      wax_return: wax_return ? 1 : 0,
      return_name: return_name || '',
      return_phone: return_phone || '',
      return_province_code: return_province_code || '',
      return_city_code: return_city_code || '',
      return_district_code: return_district_code || '',
      return_address: return_address || '',
      report_email: report_email || '',
      sample_tracking_no: sample_tracking_no || '',
      sample_photos: JSON.stringify(sample_photos || []),
      sign_income: sign_income || '',
      sign_privacy: sign_privacy || '',
      sign_promise: sign_promise || '',
      sign_privacy_jhr: sign_privacy_jhr || '',
      income_amount: income_amount || '',
      guardian_name: guardian_name || '',
      guardian_id_card: guardian_id_card || '',
      guardian_relation: guardian_relation || '',
      status: 1,
      create_by: this.adminUser?.id || 0
    });

    // 记录审核日志（后台新增直接审核通过）
    await this.model('patient_audit').add({
      patient_id: id,
      action: 'approve',
      operator_id: this.adminUser?.id || 0,
      operator_name: this.adminUser?.nickname || this.adminUser?.username || ''
    });

    await this.log('add', '患者管理', `新增患者「${name}」编号:${patientNo}`);
    return this.success({ id, patient_no: patientNo });
  }

  // 审核通过
  async approveAction() {
    const { id } = this.post();
    if (!id) return this.fail('参数错误');

    const patient = await this.model('patient')
      .where({ id, is_deleted: 0 })
      .find();

    if (think.isEmpty(patient)) return this.fail('患者不存在');
    if (patient.status === 1) return this.fail('该患者已审核通过');

    await this.model('patient').where({ id }).update({
      status: 1,
      update_by: this.adminUser?.id || 0
    });

    await this.model('patient_audit').add({
      patient_id: id,
      action: 'approve',
      operator_id: this.adminUser?.id || 0,
      operator_name: this.adminUser?.nickname || this.adminUser?.username || ''
    });

    // 发送消息通知
    await this.model('message').add({
      patient_id: id,
      type: 1,
      title: '审核通过',
      content: AUDIT_APPROVED_CONTENT,
      reason: ''
    });

    // 发送订阅消息
    await this._sendAuditSubscribeMessage(id, patient.name, '审核通过');

    // 发送短信通知
    await this._sendAuditSms(patient.phone, 'approved');

    await this.log('edit', '患者管理', `审核通过患者(ID:${id})`);
    return this.success();
  }

  // 驳回
  async rejectAction() {
    const { id, reason } = this.post();
    if (!id) return this.fail('参数错误');
    if (!reason) return this.fail('请填写驳回原因');

    const patient = await this.model('patient')
      .where({ id, is_deleted: 0 })
      .find();

    if (think.isEmpty(patient)) return this.fail('患者不存在');
    if (patient.status === 2) return this.fail('该患者已被驳回');

    await this.model('patient').where({ id }).update({
      status: 2,
      update_by: this.adminUser?.id || 0
    });

    await this.model('patient_audit').add({
      patient_id: id,
      action: 'reject',
      reason,
      operator_id: this.adminUser?.id || 0,
      operator_name: this.adminUser?.nickname || this.adminUser?.username || ''
    });

    // 发送消息通知
    await this.model('message').add({
      patient_id: id,
      type: 2,
      title: '审核未通过',
      content: '您提交的个人资料未通过审核，请根据以下原因修改后重新提交。',
      reason: reason
    });

    // 发送订阅消息
    await this._sendAuditSubscribeMessage(id, patient.name, '审核驳回');

    // 发送短信通知
    await this._sendAuditSms(patient.phone, 'rejected', reason);

    await this.log('edit', '患者管理', `驳回患者(ID:${id})，原因：${reason}`);
    return this.success();
  }

  // 删除患者（软删除，支持批量）
  async deleteAction() {
    const { ids } = this.post();
    if (!ids || !ids.length) return this.fail('参数错误');

    const model = this.model('patient');
    const patients = await model.where({ id: ['in', ids], is_deleted: 0 }).select();
    if (!patients.length) return this.fail('患者不存在');

    await model.where({ id: ['in', ids] }).update({
      is_deleted: 1,
      update_by: this.adminUser?.id || 0
    });

    // 清除 wechat_user 表中的患者关联，避免用户重新认证时走 update 逻辑
    await this.model('wechat_user')
      .where({ patient_id: ['in', ids] })
      .update({ patient_id: 0 });

    const names = patients.map(p => p.name).join('、');
    await this.log('delete', '患者管理', `删除患者「${names}」共${patients.length}条`);
    return this.success();
  }

  async resetSampleInfoAction() {
    if (!this._canEditPatient()) return this.fail('暂无权限');
    const { id } = this.post();
    if (!id) return this.fail('参数错误');

    const patient = await this.model('patient').where({ id, is_deleted: 0 }).find();
    if (think.isEmpty(patient)) return this.fail('患者不存在');

    await this.model('patient').where({ id }).update({
      sample_info_status: 0,
      sample_edit_reason: '',
      sample_edit_reject_reason: '',
      sample_edit_apply_time: null,
      sample_edit_audit_time: null,
      update_by: this.adminUser?.id || 0
    });

    await this._addSampleLog(id, 'sample_reset_edit', '重置送检信息编辑', '后台重置送检信息为可修改');
    await this.log('edit', '患者管理', `重置送检信息编辑权限(ID:${id})`);
    return this.success();
  }

  async saveReturnTrackingNoAction() {
    if (!this._canEditPatient()) return this.fail('暂无权限');
    const { id, return_tracking_no } = this.post();
    if (!id) return this.fail('参数错误');
    if (!return_tracking_no || !return_tracking_no.trim()) return this.fail('请填写回寄物流单号');

    const patient = await this.model('patient').where({ id, is_deleted: 0 }).find();
    if (think.isEmpty(patient)) return this.fail('患者不存在');
    if (!patient.wax_return) return this.fail('该患者未选择样本寄回');
    if (![1, 2].includes(Number(patient.sample_info_status))) return this.fail('送检信息未生效，暂不能填写回寄物流单号');

    const trackingNo = return_tracking_no.trim();
    const now = think.datetime(new Date());
    await this.model('patient').where({ id }).update({
      sample_info_status: 2,
      return_tracking_no: trackingNo,
      return_time: now,
      update_by: this.adminUser?.id || 0
    });

    await this.model('message').where({ patient_id: id, type: 3 }).delete();
    await this.model('message').add({
      patient_id: id,
      type: 3,
      title: '回寄信息',
      content: '样品已经寄回，请注意查收。',
      reason: trackingNo,
      is_read: 0
    });

    await this._addSampleLog(id, 'sample_return', Number(patient.sample_info_status) === 2 ? '修改回寄物流单号' : '填写回寄物流单号', `回寄物流单号：${trackingNo}`);
    await this.log('edit', '患者管理', `填写回寄物流单号(ID:${id})：${trackingNo}`);
    return this.success();
  }

  async approveSampleEditAction() {
    if (!this._canEditPatient()) return this.fail('暂无权限');
    const { id } = this.post();
    if (!id) return this.fail('参数错误');

    const patient = await this.model('patient').where({ id, is_deleted: 0 }).find();
    if (think.isEmpty(patient)) return this.fail('患者不存在');
    if (Number(patient.sample_info_status) !== 3) return this.fail('当前没有待审核的送检修改申请');

    const reason = patient.sample_edit_reason || '';
    await this.model('patient').where({ id }).update({
      sample_info_status: 0,
      sample_edit_reason: '',
      sample_edit_reject_reason: '',
      sample_edit_apply_time: null,
      sample_edit_audit_time: null,
      update_by: this.adminUser?.id || 0
    });

    await this._addSampleLog(id, 'sample_approve_edit', '送检修改申请通过', '后台通过送检信息修改申请，患者可重新编辑送检信息', reason);
    await this._addSampleEditMessage(id, true);
    await this._sendSampleEditSubscribeMessage(id, patient.name, '审核通过', '请重新提交送检信息');
    await this.log('edit', '患者管理', `通过送检信息修改申请(ID:${id})`);
    return this.success();
  }

  async rejectSampleEditAction() {
    if (!this._canEditPatient()) return this.fail('暂无权限');
    const { id, reason } = this.post();
    if (!id) return this.fail('参数错误');
    if (!reason || !reason.trim()) return this.fail('请填写驳回原因');

    const patient = await this.model('patient').where({ id, is_deleted: 0 }).find();
    if (think.isEmpty(patient)) return this.fail('患者不存在');
    if (Number(patient.sample_info_status) !== 3) return this.fail('当前没有待审核的送检修改申请');

    const rejectReason = reason.trim();
    const now = think.datetime(new Date());
    await this.model('patient').where({ id }).update({
      sample_info_status: 1,
      sample_edit_reject_reason: rejectReason,
      sample_edit_audit_time: now,
      update_by: this.adminUser?.id || 0
    });

    await this._addSampleLog(id, 'sample_reject_edit', '送检修改申请驳回', '后台驳回送检信息修改申请', rejectReason);
    await this._addSampleEditMessage(id, false, rejectReason);
    await this._sendSampleEditSubscribeMessage(id, patient.name, '审核拒绝', '修改申请未通过，请查看详情');
    await this.log('edit', '患者管理', `驳回送检信息修改申请(ID:${id})，原因：${rejectReason}`);
    return this.success();
  }

  async editSampleInfoAction() {
    if (!this._canEditPatient()) return this.fail('暂无权限');
    const data = this.post();
    const { id, sample_types, wax_return, return_name, return_phone, return_province_code, return_city_code, return_district_code, return_address, report_email, sample_tracking_no, sample_photos } = data;
    if (!id) return this.fail('参数错误');

    const patient = await this.model('patient').where({ id, is_deleted: 0 }).find();
    if (think.isEmpty(patient)) return this.fail('患者不存在');

    const finalSampleTypes = this._parseArrayValue(sample_types);
    const finalSamplePhotos = this._parseArrayValue(sample_photos);
    const hasSample = finalSampleTypes.length > 0;
    const needReturn = hasSample && Number(wax_return) === 1;
    const finalReportEmail = hasSample ? (report_email || '').trim() : '';

    if (needReturn) {
      if (!return_name || !return_name.trim()) return this.fail('请填写回寄收件人');
      if (!return_phone || !return_phone.trim()) return this.fail('请填写回寄收件电话');
      if (!return_province_code || !return_city_code || !return_district_code) return this.fail('请选择回寄收件地址');
      if (!return_address || !return_address.trim()) return this.fail('请填写回寄详细地址');
    }
    if (finalReportEmail) {
      if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(finalReportEmail)) return this.fail('邮箱格式不正确');
      const dup = await this.model('patient')
        .where({ report_email: finalReportEmail, is_deleted: 0, id: ['!=', id] })
        .find();
      if (!think.isEmpty(dup)) return this.fail('该邮箱已被其他患者使用');
    }

    await this.model('patient').where({ id }).update({
      sample_types: JSON.stringify(finalSampleTypes),
      wax_return: needReturn ? 1 : 0,
      return_name: needReturn ? (return_name || '').trim() : '',
      return_phone: needReturn ? (return_phone || '').trim() : '',
      return_province_code: needReturn ? (return_province_code || '') : '',
      return_city_code: needReturn ? (return_city_code || '') : '',
      return_district_code: needReturn ? (return_district_code || '') : '',
      return_address: needReturn ? (return_address || '').trim() : '',
      report_email: hasSample ? finalReportEmail : '',
      sample_tracking_no: hasSample ? (sample_tracking_no || '').trim() : '',
      sample_photos: hasSample ? JSON.stringify(finalSamplePhotos) : '[]',
      sample_info_status: 1,
      return_tracking_no: '',
      return_time: null,
      sample_edit_reason: '',
      sample_edit_reject_reason: '',
      sample_edit_apply_time: null,
      sample_edit_audit_time: null,
      update_by: this.adminUser?.id || 0
    });

    await this._addSampleLog(id, 'sample_admin_edit', '后台编辑送检信息', '后台直接编辑送检信息，状态已生效');
    await this.log('edit', '患者管理', `后台编辑送检信息(ID:${id})`);
    return this.success();
  }

  // 编辑患者
  async editAction() {
    const data = this.post();
    const { id, name, phone, id_card, gender, birth_date, province_code, city_code, district_code, address, hospital, hospital_province_code, hospital_city_code, hospital_district_code, emergency_contact, emergency_phone, tag, documents, sample_types, wax_return, return_name, return_phone, return_province_code, return_city_code, return_district_code, return_address, report_email, sample_tracking_no, sample_photos, sign_income, sign_privacy, sign_promise, sign_privacy_jhr, income_amount, guardian_name, guardian_id_card, guardian_relation } = data;

    if (!id) return this.fail('参数错误');
    if (!name || !phone || !id_card || !gender || !birth_date) return this.fail('请填写完整信息');
    if (!province_code || !city_code || !district_code) return this.fail('请选择省市区');
    if (!address) return this.fail('请填写详细地址');
    if (!/^1\d{10}$/.test(phone)) return this.fail('手机号格式不正确');
    if (!/^\d{17}[\dXx]$/.test(id_card)) return this.fail('身份证号格式不正确');

    const patient = await this.model('patient').where({ id, is_deleted: 0 }).find();
    if (think.isEmpty(patient)) return this.fail('患者不存在');

    // 唯一性校验（排除自身）
    const existByPhone = await this.model('patient').where({ phone, id: ['!=', id], is_deleted: 0 }).find();
    if (!think.isEmpty(existByPhone)) return this.fail('该手机号已被其他患者使用');
    const existByIdCard = await this.model('patient').where({ id_card, id: ['!=', id], is_deleted: 0 }).find();
    if (!think.isEmpty(existByIdCard)) return this.fail('该身份证号已被其他患者使用');

    await this.model('patient').where({ id }).update({
      name, phone, id_card, gender, birth_date,
      province_code, city_code, district_code,
      address: address || '',
      hospital: hospital || '',
      hospital_province_code: hospital_province_code || '',
      hospital_city_code: hospital_city_code || '',
      hospital_district_code: hospital_district_code || '',
      emergency_contact: emergency_contact || '',
      emergency_phone: emergency_phone || '',
      tag: tag || '',
      documents: JSON.stringify(documents || []),
      sample_types: JSON.stringify(sample_types || []),
      wax_return: wax_return ? 1 : 0,
      return_name: return_name || '',
      return_phone: return_phone || '',
      return_province_code: return_province_code || '',
      return_city_code: return_city_code || '',
      return_district_code: return_district_code || '',
      return_address: return_address || '',
      report_email: report_email || '',
      sample_tracking_no: sample_tracking_no || '',
      sample_photos: JSON.stringify(sample_photos || []),
      sign_income: sign_income || '',
      sign_privacy: sign_privacy || '',
      sign_promise: sign_promise || '',
      sign_privacy_jhr: sign_privacy_jhr || '',
      income_amount: income_amount || '',
      guardian_name: guardian_name || '',
      guardian_id_card: guardian_id_card || '',
      guardian_relation: guardian_relation || '',
      update_by: this.adminUser?.id || 0
    });

    await this.log('edit', '患者管理', `编辑患者「${name}」(ID:${id})`);
    return this.success();
  }

  // 导出患者数据（CSV，不脱敏）
  async exportAction() {
    const { keyword, tag, status, startDate, endDate, province_code, city_code, district_code } = this.get();
    const model = this.model('patient');
    const list = await model.getAll({ keyword, tag, status, startDate, endDate, province_code, city_code, district_code });

    // 批量查省市区名称（包含寄回地址）
    const allCodes = new Set();
    list.forEach(item => {
      if (item.province_code) allCodes.add(item.province_code);
      if (item.city_code) allCodes.add(item.city_code);
      if (item.district_code) allCodes.add(item.district_code);
      if (item.return_province_code) allCodes.add(item.return_province_code);
      if (item.return_city_code) allCodes.add(item.return_city_code);
      if (item.return_district_code) allCodes.add(item.return_district_code);
      if (item.hospital_province_code) allCodes.add(item.hospital_province_code);
      if (item.hospital_city_code) allCodes.add(item.hospital_city_code);
      if (item.hospital_district_code) allCodes.add(item.hospital_district_code);
    });
    const regionMap = {};
    if (allCodes.size) {
      const regions = await this.model('sys_region')
        .where({ code: ['in', [...allCodes]] })
        .select();
      regions.forEach(r => { regionMap[r.code] = r.name; });
    }

    // 批量查最近一条审核记录（审核日期、驳回原因）
    const patientIds = list.map(item => item.id);
    const auditMap = {};
    if (patientIds.length) {
      const audits = await this.model('patient_audit')
        .where({ patient_id: ['in', patientIds], action: ['in', ['approve', 'reject']] })
        .order('id DESC')
        .select();
      audits.forEach(a => {
        if (!auditMap[a.patient_id]) auditMap[a.patient_id] = a;
      });
    }

    const statusMap = { '-1': '待提交', 0: '待审核', 1: '审核通过', 2: '已驳回' };
    const header = [
      'ID', '姓名', '性别', '身份证', '手机号', '省份', '城市', '详细地址',
      '医院名称', '医院省份', '医院城市', '医院区县', '紧急联系人', '紧急联系电话', '瘤种',
      '送检样本类型', '是否需寄回', '收件人', '收件电话', '收件地址',
      '报告接收邮箱', '送检物流单号',
      '提交时间', '审核状态', '审核日期', '审核驳回原因'
    ];

    const ExcelJS = require('exceljs');
    const workbook = new ExcelJS.Workbook();
    const sheet = workbook.addWorksheet('患者信息');

    // 表头
    sheet.addRow(header);
    // 表头样式：绿色背景、白色加粗字体、冻结首行
    const headerRow = sheet.getRow(1);
    const colCount = header.length;
    for (let i = 1; i <= colCount; i++) {
      const cell = headerRow.getCell(i);
      cell.font = { bold: true, color: { argb: 'FFFFFFFF' } };
      cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF4CAF50' } };
      cell.alignment = { vertical: 'middle', horizontal: 'center' };
    }
    sheet.views = [{ state: 'frozen', ySplit: 1 }];

    // 边框样式
    const thinBorder = {
      top: { style: 'thin' },
      left: { style: 'thin' },
      bottom: { style: 'thin' },
      right: { style: 'thin' }
    };
    // 表头加边框
    for (let i = 1; i <= colCount; i++) {
      headerRow.getCell(i).border = thinBorder;
    }

    // 数据行
    list.forEach(item => {
      const audit = auditMap[item.id];
      let sampleTypes = '';
      try { sampleTypes = JSON.parse(item.sample_types || '[]').join('、'); } catch (e) { sampleTypes = ''; }
      const returnAddr = item.return_address
        ? [regionMap[item.return_province_code] || '', regionMap[item.return_city_code] || '', regionMap[item.return_district_code] || '', item.return_address].filter(Boolean).join('')
        : '';

      const row = sheet.addRow([
        item.patient_no,
        item.name,
        item.gender,
        item.id_card,
        item.phone,
        regionMap[item.province_code] || '',
        regionMap[item.city_code] || '',
        item.address || '',
        item.hospital || '',
        regionMap[item.hospital_province_code] || '',
        regionMap[item.hospital_city_code] || '',
        regionMap[item.hospital_district_code] || '',
        item.emergency_contact || '',
        item.emergency_phone || '',
        item.tag || '',
        sampleTypes,
        item.wax_return ? '是' : '否',
        item.return_name || '',
        item.return_phone || '',
        returnAddr,
        item.report_email || '',
        item.sample_tracking_no || '',
        item.create_time || '',
        statusMap[item.status] || '',
        audit ? (audit.create_time || '') : '',
        (audit && audit.action === 'reject') ? (audit.reason || '') : ''
      ]);
      // 数据行加边框
      for (let i = 1; i <= colCount; i++) {
        row.getCell(i).border = thinBorder;
      }
    });

    // 自动列宽
    sheet.columns.forEach(col => {
      let maxLen = 10;
      col.eachCell({ includeEmpty: true }, cell => {
        const len = String(cell.value || '').length;
        if (len > maxLen) maxLen = len;
      });
      col.width = Math.min(maxLen + 4, 40);
    });

    const buffer = await workbook.xlsx.writeBuffer();
    const ts = dayjs().format('YYYYMMDDHHmmss');
    const fileName = encodeURIComponent(`患者信息_${ts}.xlsx`);

    this.ctx.set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
    this.ctx.set('Content-Disposition', `attachment; filename*=UTF-8''${fileName}`);
    this.ctx.body = Buffer.from(buffer);

    await this.log('export', '患者管理', `导出患者数据 ${list.length} 条`);
  }

  // @private 发送审核结果订阅消息
  async _sendAuditSubscribeMessage(patientId, patientName, result) {
    try {
      // 查找该患者关联的微信用户
      const wechatUser = await this.model('wechat_user')
        .where({ patient_id: patientId, app_remark: APP_REMARK, status: 1 })
        .find();
      if (think.isEmpty(wechatUser) || !wechatUser.open_id) return;

      const wechatService = this.service('wechat');
      const templates = await wechatService.getSubscribeTemplates(APP_REMARK);
      const templateId = templates.audit_result;
      if (!templateId) return;

      // 映射小程序版本: __wxConfig.envVersion -> miniprogram_state
      // develop -> developer, trial -> trial, release -> formal
      const envMap = { develop: 'developer', trial: 'trial', release: 'formal' };
      const miniprogramState = envMap[wechatUser.mp_env_version] || 'formal';

      const dayjs = require('dayjs');
      await wechatService.sendSubscribeMessage({
        remark: APP_REMARK,
        openid: wechatUser.open_id,
        templateId,
        page: 'pages/profile/profile',
        miniprogramState,
        data: {
          thing2: { value: '肠愈同行患者关爱' },
          thing14: { value: patientName || '用户' },
          phrase1: { value: result },
          time13: { value: dayjs().format('YYYY-MM-DD HH:mm:ss') }
        }
      });
    } catch (error) {
      // 订阅消息发送失败不影响审核流程
      think.logger.error('[Subscribe] 审核消息发送失败:', error);
    }
  }

  async _addSampleEditMessage(patientId, approved, reason = '') {
    await this.model('message').add({
      patient_id: patientId,
      type: 4,
      title: approved ? '送检信息修改申请已通过' : '送检信息修改申请未通过',
      content: approved
        ? '您的送检信息修改申请已通过，请前往送检信息页面重新提交。'
        : '您的送检信息修改申请未通过，请查看原因。',
      reason: approved ? '' : reason,
      is_read: 0
    });
  }

  // @private 发送送检修改申请审核结果订阅消息
  async _sendSampleEditSubscribeMessage(patientId, patientName, result, remark) {
    try {
      const wechatUser = await this.model('wechat_user')
        .where({ patient_id: patientId, app_remark: APP_REMARK, status: 1 })
        .find();
      if (think.isEmpty(wechatUser) || !wechatUser.open_id) return;

      const wechatService = this.service('wechat');
      const templates = await wechatService.getSubscribeTemplates(APP_REMARK);
      const templateId = templates.sample_edit_audit || SAMPLE_EDIT_AUDIT_TEMPLATE_ID;
      if (!templateId) return;

      const envMap = { develop: 'developer', trial: 'trial', release: 'formal' };
      const miniprogramState = envMap[wechatUser.mp_env_version] || 'formal';
      const limitThing = value => String(value || '').slice(0, 20);
      await wechatService.sendSubscribeMessage({
        remark: APP_REMARK,
        openid: wechatUser.open_id,
        templateId,
        page: 'pages/profile/profile',
        miniprogramState,
        data: {
          thing4: { value: limitThing(remark || '送检信息修改申请已处理') },
          phrase1: { value: result },
          thing16: { value: limitThing(patientName || '患者') },
          time13: { value: dayjs().format('YYYY-MM-DD HH:mm:ss') }
        }
      });
    } catch (error) {
      think.logger.error('[Subscribe] 送检修改申请审核消息发送失败:', error);
    }
  }

  // @private 发送审核结果短信通知
  async _sendAuditSms(phone, type, reason) {
    if (!phone) return;
    try {
      const smsConfig = require('../../config/sms.js');
      const templates = smsConfig.templates;
      think.logger.info(`[SMS] _sendAuditSms 开始 - phone: ${phone}, type: ${type}, reason: ${reason || '(无)'}`);
      think.logger.info(`[SMS] 模板配置 - auditApproved: ${templates.auditApproved || '(空)'}, auditRejected: ${templates.auditRejected || '(空)'}`);
      if (type === 'approved' && templates.auditApproved) {
        await this.sendNotifySms(phone, templates.auditApproved, [], 'audit_approved');
      } else if (type === 'rejected' && templates.auditRejected) {
        // 驳回原因截取前15字符（短信模板变量有长度限制）
        const shortReason = (reason || '资料不符合要求').slice(0, 15);
        await this.sendNotifySms(phone, templates.auditRejected, [shortReason], 'audit_rejected');
      }
    } catch (error) {
      think.logger.error('[SMS] 审核短信发送失败:', error);
    }
  }

};
