package com.ywt.outpatient.service.rpc;

import com.ywt.biz.common.enums.*;
import com.ywt.biz.common.util.Checker;
import com.ywt.biz.common.util.DateUtil;
import com.ywt.biz.common.util.StringHelper;
import com.ywt.biz.common.util.serializers.JsonSerializer;
import com.ywt.gapi.consult.FreeConsultDoctorInfo;
import com.ywt.gapi.im.IMService;
import com.ywt.gapi.im.SessionMessage;
import com.ywt.outpatient.core.BaseResponse;
import com.ywt.outpatient.core.PagedList;
import com.ywt.outpatient.core.SqlHelper;
import com.ywt.outpatient.domain.entity.center.*;
import com.ywt.outpatient.domain.models.config.ConstantTemplateIds;
import com.ywt.outpatient.core.Constants;
import com.ywt.outpatient.domain.models.enums.AccountDetailTypeEnum;
import com.ywt.outpatient.domain.models.enums.CommonBillTypeEnum;
import com.ywt.outpatient.domain.models.enums.ConsultStatusEnum;
import com.ywt.outpatient.domain.wechat.Keyword;
import com.ywt.outpatient.service.rpc.common.SmsProvider;
import com.ywt.outpatient.service.rpc.common.WeChatMsgProvider;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.apache.dubbo.config.annotation.DubboReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.stereotype.Service;

import javax.persistence.EntityManager;
import javax.persistence.ParameterMode;
import javax.persistence.StoredProcedureQuery;
import java.math.BigDecimal;
import java.sql.Types;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.TextStyle;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author daiyihua
 * @create 2019-01-28 3:18 PM
 * @desc 咨询订单相关
 **/

@Service
public class ConsultingService {

    private static final Logger logger = LoggerFactory.getLogger(ConsultingService.class);

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private ConsultOrderViewRepository consultOrderViewRepository;

    @Autowired
    private AccountRepository accountRepository;

    @Autowired
    private EntityManager entityManager;

    @Autowired
    private SqlHelper sqlHelper;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private MedicalRecordsImageRepository medicalRecordsImageRepository;

    @Autowired
    private SmsProvider smsProvider;

    @DubboReference
    private IMService imServiceBlockingStub;

    @Autowired
    private WeChatMsgProvider weChatMsgProvider;

    @Autowired
    private DoctorFreeConsultScheduleRepository doctorFreeConsultScheduleRepository;

    @Autowired
    private DoctorRepository doctorRepository;

    @Autowired
    private DoctorService doctorService;

    /**
     * 微问诊订单退款状态修改
     *
     * @param orderId
     */
    public void updateMicroConsultStatusRefunded(int orderId) {
        try {
            String sql = "update micro_consult set status = 1 where  order_id = ? and order_type = ? ;";
            Object[] args = new Object[]{orderId, OrderTypeEnum.CONSULT.getValue()};
            int[] types = new int[]{Types.INTEGER, Types.INTEGER};
            jdbcTemplate.update(sql, args, types);
        } catch (Exception e) {
            logger.error("updateMicroConsultStatus:{}", orderId, e.getMessage(), e);
        }
    }


    /**
     * 去掉问诊订单已结算的状态
     *
     * @param consultOrderId
     */
    private BaseResponse updateConsultGiveupSettlementStatus(int consultOrderId) {
        BaseResponse response = new BaseResponse();
        try {
            String sql = "update consult_order set consult_status = (consult_status &~ ?) where id = ?";
            Object[] args = new Object[]{ConsultStatusEnum.Settlement.getValue(), consultOrderId};
            int[] types = new int[]{Types.INTEGER, Types.INTEGER};
            int count = jdbcTemplate.update(sql, args, types);
            if (count > 0) {
                return response.succeed("处理成功");
            }
        } catch (Exception e) {
            logger.error("updateConsultGiveupSettlementStatus:{}", consultOrderId, e.getMessage(), e);
        }
        return response.failed(BaseResponse.APP_ERROR, "处理成功");
    }


    /**
     * 医生账户写入退款信息
     */
    public BaseResponse updateDoctorAccount(int id) {
        BaseResponse baseResponse = new BaseResponse();
        ConsultOrderView order = consultOrderViewRepository.findById(id).orElse(null);

        Account account = null;
        AccountDetail detail = null;
        // 如果订单是已结算的状态，那么需要从医生账户里面扣掉钱再说
        if ((order.getConsultStatus() & ConsultStatusEnum.Settlement.getValue()) == ConsultStatusEnum.Settlement.getValue()) {

            account = accountRepository.getByUserId(order.getDoctorId());
            if (Checker.isNone(account)) {
                return baseResponse.failed(BaseResponse.PARAMETER_ERROR, "参数错误");
            }
            BigDecimal bigDecimal = new BigDecimal("100");
            bigDecimal = bigDecimal.multiply(order.getOrderAmount());
            int amount = bigDecimal.intValue();
            int balance = account.getBalance() - amount;
            if (balance < 0) {
                logger.error("医生账户余额小于退款金额", order.toString());
                return baseResponse.failed(BaseResponse.PARAMETER_ERROR, "医生账户余额小于退款金额");
            }

            /*
            account.setBalance(balance);
            detail = new AccountDetail();
            int detailId = idGenerator.genAccountDetailId();
            detail.setId(detailId);
            detail.setBalance(balance);
            detail.setAccountId(account.getId());
            detail.setUserId(order.getDoctorId());
            detail.setAmount(-amount);
            detail.setStatus(1);
            detail.setCreateTime(new Date());
            detail.setDeleted(false);
            detail.setType(AccountDetailTypeEnum.Refund.getValue());
            detail.setRemark(AccountDetailTypeEnum.Refund.getDisplayName());
            detail.setTitle("咨询退款");

            accountRepository.save(account);
            accountDetailRepository.save(detail);

            int consultStatus = order.getConsultStatus();
            // 处理咨询订单状态（去掉已结算）
             */
            StoredProcedureQuery storedProcedureQuery = entityManager.createStoredProcedureQuery("add_user_account_detail")
                    .registerStoredProcedureParameter("user_id", Integer.class, ParameterMode.IN)
                    .registerStoredProcedureParameter("type", Integer.class, ParameterMode.IN)
                    .registerStoredProcedureParameter("amount", Integer.class, ParameterMode.IN)
                    .registerStoredProcedureParameter("title", String.class, ParameterMode.IN)
                    .registerStoredProcedureParameter("remark", String.class, ParameterMode.IN)
                    .registerStoredProcedureParameter("object_id", String.class, ParameterMode.IN)
                    .registerStoredProcedureParameter("result_code", Integer.class, ParameterMode.OUT)
                    .registerStoredProcedureParameter("total_balance", Integer.class, ParameterMode.OUT)
                    .setParameter("user_id", order.getDoctorId())
                    .setParameter("type", AccountDetailTypeEnum.Refund.getValue())
                    .setParameter("amount", -amount)
                    .setParameter("title", AccountDetailTypeEnum.Refund.getDisplayName())
                    .setParameter("remark", "管理后台咨询退款")
                    .setParameter("object_id", String.valueOf(order.getOrderId()));
            storedProcedureQuery.execute();
            Integer resultCode = (Integer) storedProcedureQuery.getOutputParameterValue("result_code");
            Integer totalBalance = (Integer) storedProcedureQuery.getOutputParameterValue("total_balance");
            if (resultCode == 0) {

                // 去掉已结算的状态
                BaseResponse response = updateConsultGiveupSettlementStatus(order.getConsultId());
                if (response.getCode() == BaseResponse.SUCCEED) {
                    return baseResponse.succeed("操作成功");
                }
                logger.error("医生账户操作成功，咨询状态处理失败", order.toString());
                return baseResponse.failed(BaseResponse.APP_ERROR, "医生账户操作成功，咨询状态处理失败");
            } else {
                logger.error("医生账户操作失败", order.toString());
                return baseResponse.failed(BaseResponse.APP_ERROR, "医生账户操作失败");
            }
        }
        return baseResponse.succeed("处理成功");
    }

    public PagedList<ConsultOrderView> getConsultOrderPagedList(int pageIndex, int pageSize, int userId, int hospitalId) {
        List<Object> paramList = new ArrayList<>();
        String whereSql = " user_id = ? ";
        paramList.add(userId);
        if (hospitalId > 0) {
            whereSql += " and hospital_id = ? ";
            paramList.add(hospitalId);
        }
        return sqlHelper.getPagedList(pageIndex, pageSize, "*", whereSql, " consult_id desc ", ConsultOrderView.class, paramList.toArray());
    }

    /**
     * 获取最近一次接诊的咨询订单
     */
    public ConsultOrderView getLatestAcceptedConsultOrder(int doctorId, int userId) {
        return consultOrderViewRepository.getLatestAcceptedConsultOrder(doctorId, userId);
    }


    /**
     * 获取询诊订单状态(新增评价)
     *
     * @param consultOrder
     * @return
     */
    public Map<String, Integer> getConsultStatusNameWithEvaluate(ConsultOrderView consultOrder) {
        return getConsultStatusNameWithEvaluate(consultOrder.getPaymentStatus(), consultOrder.getConsultStatus(),
                consultOrder.getAcceptTime(), consultOrder.getCreateTime(), consultOrder.getPayTime());
    }

    public Map<String, Integer> getConsultStatusNameWithEvaluate(int paymentStatus, int consultStatus, Date acceptTime,
                                                                 Date createTime, Date payTime) {
        Map<String, Integer> map = new HashMap<>();

        if (paymentStatus != PaymentStatusEnum.Success.getValue()) {
            map.put("待支付", 1);
            return map;
        }

        if ((consultStatus & ConsultStatusEnum.Refunded.getValue()) == ConsultStatusEnum.Refunded.getValue()) {
            map.put("已退款", 8);
            return map;
        }

        if ((consultStatus & ConsultStatusEnum.Cancel.getValue()) == ConsultStatusEnum.Cancel.getValue()) {
            map.put("已取消", 2);
            return map;
        }

        if ((consultStatus & ConsultStatusEnum.Refuse.getValue()) == ConsultStatusEnum.Refuse.getValue()) {
            map.put("已退诊", 3);
            return map;
        }

        if ((consultStatus & ConsultStatusEnum.Evaluate.getValue()) == ConsultStatusEnum.Evaluate.getValue()) {
            map.put("已评价", 7);
            return map;
        }

        // 结束但未评价 --》 待评价   add start
        if ((consultStatus & ConsultStatusEnum.End.getValue()) == ConsultStatusEnum.End.getValue() &&
                (consultStatus & ConsultStatusEnum.Evaluate.getValue()) != ConsultStatusEnum.Evaluate.getValue()) {
            map.put("待评价", 9);
            return map;
        }
        // end add

        if ((consultStatus & ConsultStatusEnum.End.getValue()) == ConsultStatusEnum.End.getValue()) {
            map.put("已结束", 4);
            return map;
        }

        if ((consultStatus & ConsultStatusEnum.Accept.getValue()) == ConsultStatusEnum.Accept.getValue()) {
            Calendar ca1 = Calendar.getInstance();
            Calendar ca2 = Calendar.getInstance();

            ca1.setTime(acceptTime);
            // 需求改动：
            // v3.3.1 改为 24 小时
            ca1.add(Calendar.DATE, 1);

            if (ca2.after(ca1)) {
                //map.put("已结束", 4);  //接诊后超过48小时医生未结束问诊
                map.put("待评价", 9);  //接诊后超过48小时医生未结束问诊
                return map;
            }

            map.put("接诊中", 5);
            return map;
        }
        if ((consultStatus & ConsultStatusEnum.Paid.getValue()) == ConsultStatusEnum.Paid.getValue()) {
            Calendar ca1 = Calendar.getInstance();
            Calendar ca2 = Calendar.getInstance();

            ca1.setTime(payTime);
            // 需求改动：
            // v3.3.1 改为 24 小时，按支付时间算
            ca1.add(Calendar.DATE, 1);

            if (ca2.before(ca1)) {
                map.put("待接诊", 6);  //接诊后超过48小时医生未结束问诊
                return map;
            }
        }

        map.put("已结束", 4);
        return map;
    }

    /**
     * 获取咨询订单在医生端显示的状态（待接诊、接诊中、已退诊、已取消、已结束、已退款）
     * 1-待支付
     * 2-已取消
     * 3-已退诊
     * 4-已结束
     * 5-接诊中
     * 6-待接诊
     * 7-已评价
     * 8-已退款
     * 9-待评价
     *
     * @param consultOrder
     * @return
     */
    public Map<String, Integer> getConsultStatusNameForDoctor(ConsultOrder consultOrder) {
        int consultStatus = consultOrder.getConsultStatus();
        Map<String, Integer> map = new HashMap<>();

        if ((consultStatus & ConsultStatusEnum.Refunded.getValue()) == ConsultStatusEnum.Refunded.getValue()) {
            map.put("已退款", 8);
            return map;
        }
        if ((consultStatus & ConsultStatusEnum.Cancel.getValue()) == ConsultStatusEnum.Cancel.getValue()) {
            map.put("已取消", 2);
            return map;
        }
        if ((consultStatus & ConsultStatusEnum.Refuse.getValue()) == ConsultStatusEnum.Refuse.getValue()) {
            map.put("已退诊", 3);
            return map;
        }
        if ((consultStatus & ConsultStatusEnum.End.getValue()) == ConsultStatusEnum.End.getValue()) {
            map.put("已结束", 4);
            return map;
        }

        Instant instant;
        LocalDateTime dateTime;
        LocalDateTime now = LocalDateTime.now();

        if ((consultStatus & ConsultStatusEnum.Accept.getValue()) == ConsultStatusEnum.Accept.getValue()) {
            instant = consultOrder.getAcceptTime().toInstant();
            dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
            // 需求改动
            // v3.3.1: 接诊后 24 小时自动结束咨询
            if (now.isAfter(dateTime.plusDays(1L))) {
                map.put("已结束", 4);  //接诊后超过48小时医生未结束问诊，标记订单为已结束
                return map;
            }

            map.put("接诊中", 5);
            return map;
        }

        Date payTime = consultOrder.getPayTime();
        if (payTime != null) {
            instant = payTime.toInstant();
            dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
            // 需求改动
            // v3.3.1: 24 小时不接诊自动结束咨询，按支付时间算
            if (now.isAfter(dateTime.plusDays(1L))) {
                map.put("已结束", 4);  //医生超过48小时未接诊，标记订单为已结束
                return map;
            }
        }

        map.put("待接诊", 6);
        return map;
    }

    /**
     * 咨询订单支付成功后，消息处理
     *
     * @param consultOrder 咨询订单实体
     * @param terminal     支付终端
     * @param prepayId     prepayId
     * @param openId       openId
     */
    public void notify(ConsultOrder consultOrder, int terminal, String prepayId, String openId) {
        try {
            int orderId = consultOrder.getOrderId();
            User user = userRepository.findById(consultOrder.getDoctorId()).orElse(null);

            //发送IM聊天信息给医生
            Map<String, Object> custom = new HashMap<>();
            custom.put("biz_type", 4);
            custom.put("order_id", orderId);
            custom.put("auto", 1);  //不发送模板消息

            String text = String.format("%s，%s，%d岁。%s",
                    consultOrder.getName(),
                    SexEnum.getSexDisplayName(consultOrder.getSex()),
                    consultOrder.getAge(),
                    consultOrder.getDescription());

            int messageType;        //IM消息类型
            String content;         //IM消息内容

            List<String> imageUrls = new LinkedList<>();
            List<MedicalRecordsImage> imageList = medicalRecordsImageRepository.getListByOrderId(orderId);
            if (imageList != null && imageList.size() > 0) {
                imageUrls = imageList.stream().map(MedicalRecordsImage::getImageUrl).collect(Collectors.toList());
            }
            if (imageUrls.size() > 0) {
                Map<String, Object> cont = new HashMap<>();
                cont.put("text", text);
                cont.put("images", imageUrls);
                content = JsonSerializer.toJson(cont);
                messageType = 4;
            } else {
                content = text;
                messageType = 1;
            }
            int leadingDocId = consultOrder.getDoctorId();
            int fromUserId = consultOrder.getUserId();
            String sessionId = consultOrder.getSessionId();
            sendSessionMsg(fromUserId, leadingDocId, content, sessionId, JsonSerializer.toJson(custom), messageType,
                    Checker.getStringValue(user.getRealname()), Checker.getStringValue(consultOrder.getName()));
            //发送模板消息通知医生（医务通互联网医院公众号）
            sendTplMsg(consultOrder.getName(), consultOrder.getSex(), consultOrder.getAge(), user.getId(),
                    consultOrder.getDescription(), orderId, Checker.getIntegerValue(consultOrder.getHospitalId()));

            int teamId = Checker.getIntegerValue(consultOrder.getTeamId());
            if (teamId > 0) {
                // 团队订单，后台排班的医生也会收到 IM 和模板消息
                List<TeamDoctor> scheduledTeamDoctors = getScheduledTeamDoctors(teamId,
                        LocalDate.now(ZoneId.of("Asia/Shanghai")).getDayOfWeek().getValue());
                if (!scheduledTeamDoctors.isEmpty()) {
                    scheduledTeamDoctors.stream()
                            .filter(teamDoctor -> teamDoctor.getDoctorId() != leadingDocId)
                            .forEach(teamDoctor -> {
                                int docId = teamDoctor.getDoctorId();
                                User doc = userRepository.findById(docId).orElse(null);
                                sendSessionMsg(fromUserId, docId, content, sessionId,
                                        JsonSerializer.toJson(custom), messageType,
                                        Checker.getStringValue(doc.getRealname()),
                                        Checker.getStringValue(consultOrder.getName()));
                                //发送模板消息通知医生（医务通互联网医院公众号）
                                sendTplMsg(consultOrder.getName(), consultOrder.getSex(), consultOrder.getAge(), user.getId(),
                                        consultOrder.getDescription(), orderId, Checker.getIntegerValue(consultOrder.getHospitalId()));
                            });
                }
            }

            //发送短信通知医生
            smsProvider.notifyAfterCreateConsultOrder(user.getRealname(), consultOrder.getName(), user.getMobile(),
                    user.getId());
            int hospitalId = Checker.getIntegerValue(consultOrder.getHospitalId());
            String templateId;
            String page;
            Map<String, String> keywordMap;
            switch (hospitalId) {
                case Constants.TAIHE_HOSPITAL_ID:
                default:
                    // 支付成功后发送模板消息至"患者端小程序-南方医院太和互联网医院"
                    terminal = TerminalEnum.TAI_HE_INTERNET_HOSPITAL_PATIENT_MINI_PROGRAM.getValue();
                    templateId = ConstantTemplateIds.CONSULT_PAY_SUCCESS;
                    page = String.format(Constants.TAI_HE_INTERNET_HOSPITAL_PATIENT_MINI_PROGRAM_CONSULT_CHAT_URL, orderId);
                    keywordMap = new HashMap<>();
                    keywordMap.put("name3", consultOrder.getDoctorName());
                    keywordMap.put("thing2", "请等待医生接诊！");
                    weChatMsgProvider.sendMPSubscribeMessage(terminal, openId, templateId, page, keywordMap);
                    break;
                case Constants.NFYYBYFY_HOSPITAL_ID:
                    terminal = TerminalEnum.NFYYBYFY_WXAPP.getValue();
                    templateId = ConstantTemplateIds.CONSULT_PAY_SUCCESS_BY;
                    page = String.format(Constants.TAI_HE_INTERNET_HOSPITAL_PATIENT_MINI_PROGRAM_CONSULT_CHAT_URL, orderId);
                    keywordMap = new HashMap<>();
                    keywordMap.put("name3", consultOrder.getDoctorName());
                    keywordMap.put("thing2", "请等待医生接诊！");
                    weChatMsgProvider.sendMPSubscribeMessage(terminal, openId, templateId, page, keywordMap);
                    break;
            }
        } catch (Exception e) {
            logger.error("notify(): {}", e.getMessage(), e);
        }
    }

    private void sendSessionMsg(int fromUserId, int toUserId, String content, String sessionId, String custom, int msgType,
                                String toUserName, String fromUserName) {
        SessionMessage sessionMessage = SessionMessage.newBuilder()
                .setFromUserId(fromUserId)
                .setToUserId(toUserId)
                .setContent(content)
                .setSessionId(sessionId)
                .setCustom(custom)
                .setMsgId(StringHelper.getUUIDWithoutHyphen())
                .setTime(System.currentTimeMillis())
                .setMessageType(msgType)
                .setToUserName(toUserName)
                .setFromUserName(fromUserName)
                .build();
        imServiceBlockingStub.sendSessionMessage(sessionMessage);
    }

    public void sendTplMsg(String patientName, int patientSex, int patientAge, int userId, String desc, int orderId, int hospitalId) {
        String first = String.format("患者%s向您发起了在线咨询", patientName);
        String remark = "点击查看详情！";
        String chatUrl = "";
        String keyword1 = String.format("%s %s %d岁", patientName, SexEnum.getSexDisplayName(patientSex), patientAge);
        String miniProgram = "";
        switch (hospitalId) {
            case Constants.TAIHE_HOSPITAL_ID:
            default:
                // 支付成功后发送模板消息至"患者端小程序-南方医院太和互联网医院"
                chatUrl = String.format(Constants.TH_NET_DOCTOR_CONSULT_CHAT_URL, orderId);
//                weChatMsgProvider.sendByTpl1029(userId, first, remark, miniProgram, chatUrl, keyword1, desc);
                Map<String, Object> data = new HashMap<>();
                data.put("thing1", new Keyword(patientName));
                data.put("const5", new Keyword("患者发起了线上问诊"));
                Date date = new Date();
                String time4 = DateUtil.convertToString(date, "yyyy-MM-dd HH:mm");
                data.put("time4", new Keyword(time4));
                String tplCode = "TPL_013001";
                weChatMsgProvider.sendTpl013001(userId, tplCode, chatUrl, miniProgram, data);
                logger.info("sendTplMsg  : {}", userId);
                break;
            case Constants.NFYYBYFY_HOSPITAL_ID:
                // 白云小程序
                chatUrl = String.format(Constants.BY_NET_DOCTOR_CONSULT_CHAT_URL, orderId);
                weChatMsgProvider.sendByTpl2013(userId, first, remark, miniProgram, chatUrl, keyword1, desc);
                break;
        }
    }

    private String getDayOfWeekAlias(int dayOfWeek) {
        try {
            return DayOfWeek.of(dayOfWeek).getDisplayName(TextStyle.FULL, Locale.US).toLowerCase();
        } catch (Exception e) {
            logger.error("ConsultingService#getDayOfWeekAlias(dayOfWeek={} ):\n {}", dayOfWeek, e.getMessage(), e);
            return "";
        }
    }

    public PagedList<FreeConsultDoctorInfo> getDoctorFreeConsultPagedList(int pageIndex, int pageSize, int hospitalId,
                                                                          int terminal, String keyword, int dayOfWeek) {
        List<Object> paramList = new ArrayList<>();
        String whereSql = "(1=1) ";
        /* 原来是跟着医院走，后面变成跟着终端走
        if (hospitalId > 0) {
            whereSql += " and fcs.hospital_ids like ?";
            paramList.add("%," + hospitalId + ",%");
        }
         */
        if (terminal > 0) {
            whereSql += " and fcs.display_terminal_ids like ?";
            paramList.add("%," + terminal + ",%");
        }
        if (!Checker.isNone(keyword)) {
            whereSql += " and doctor_name like ?";
            paramList.add("%" + keyword + "%");
        }
        if (dayOfWeek > 0) {
            whereSql += String.format(" and %s > 0", getDayOfWeekAlias(dayOfWeek));
        }
        whereSql += " and deleted = 0";

        String fields = "`fcs`.`id` as `id`,`fcs`.`doctor_id` as `doctor_id`,`fcs`.`doctor_name` as `doctor_name`," +
                "`fcs`.`hospital_ids` as `hospital_ids`,`fcs`.`create_time` as `create_time`," +
                "`fcs`.`update_time` as `update_time`,`fcs`.`deleted` as `deleted`,`fcs`.`weight` as `weight`," +
                "`fcs`.`monday` as `monday`,`fcs`.`tuesday` as `tuesday`,`fcs`.`wednesday` as `wednesday`," +
                "`fcs`.`thursday` as `thursday`,`fcs`.`friday` as `friday`,`fcs`.`saturday` as `saturday`," +
                "`fcs`.`sunday` as `sunday`, `fcs`.`consult_fee` as `consult_fee`, `d`.`title` as `title`,`d`.`dept_name` as `deptName`,`d`.`avatar2` as `avatar`," +
                "`d`.`specialty` as `specialty`, d.neg_reception as neg_reception, d.neg_reception_hint as neg_reception_hint ";

        String from = "doctor_free_consult_schedule as fcs left join doctor as d on fcs.doctor_id = d.id";

        return sqlHelper.getPagedList(pageIndex, pageSize, fields, from, whereSql, " weight desc ",
                FreeConsultDoctorInfo.class, paramList.toArray());
    }

    public DoctorFreeConsultSchedule getDoctorFreeConsultInfo(int hospitalId, int terminal, int doctorId) {
        if (terminal > 0) {
            return doctorFreeConsultScheduleRepository.getByDoctorIdAndTerminal(doctorId, "%," + terminal + ",%");
        }
//        之前是要求跟着医院走，后面是要求跟着终端走
//        else if (hospitalId > 0) {
//            return doctorFreeConsultScheduleRepository.getByDoctorIdAndHospitalId(doctorId, "%," + hospitalId + ",%");
//        }
        else {
            return doctorFreeConsultScheduleRepository.getByDoctorId(doctorId);
        }
    }

    public List<TeamDoctor> getScheduledTeamDoctors(int teamId, int dayOfWeek) {
        String sql = String.format("select * from team_doctor where team_id = %d and %s > 0", teamId, getDayOfWeekAlias(dayOfWeek));
        return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(TeamDoctor.class));
    }


    /**
     * 获取当日值班医生加入的所有团队里的领衔医生 id
     *
     * @param doctorId 医生 id
     * @return 领衔医生 id 列表
     */
    public List<Integer> getJoinedTeamLeadingDocIdsByDocId(int doctorId, int dayOfWeek) {
        String sql = "select doctor_id from team where deleted = 0 and id in " +
                String.format("(select team_id from team_doctor where doctor_id = %d and deleted = 0 and status = 1 and %s > 0 )",
                        doctorId, getDayOfWeekAlias(dayOfWeek));
        logger.info("ConsultingService#getJoinedTeamLeadingDocIdsByDocId(doctorId={} , dayOfWeek={} ):\nsql: {}", doctorId, dayOfWeek, sql);
        List<Integer> results = jdbcTemplate.queryForList(sql, Integer.class);
        logger.info("ConsultingService#getJoinedTeamLeadingDocIdsByDocId(doctorId={} , dayOfWeek={} ):\nresults: {}", doctorId, dayOfWeek, results);
        return results;
    }

    public String getOrderBill(String billDate, int hospitalId) {
        String csvData = "";
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHH:mm:ss");
            Date startDate = sdf.parse(billDate + "00:00:00");
            Date endDate = sdf.parse(billDate + "23:59:59");
            String startDateStr = DateUtil.convertToString(startDate, "yyyy-MM-dd HH:mm:ss");
            String endDateStr = DateUtil.convertToString(endDate, "yyyy-MM-dd HH:mm:ss");
            String dayDate = startDateStr.split(" ")[0];

            List paramList = new ArrayList();
            List<Integer> argTypesList = new ArrayList();

            StringBuilder sql = new StringBuilder(" Select `id`, `order_no`,`amount`,`payment_no`,`refund_status`,\n" +
                    " `refund_no`,`refund_callback_time`, `create_time`,`pay_time`, `hospital_id`, `hospital_name`\n" +
                    "  from `consult_order` where `pay_time` >= ? and \n" +
                    " `pay_time` <= ? and `payment_status` = 2 and amount > 0 ");
            paramList.add(startDateStr);
            argTypesList.add(Types.VARCHAR);

            paramList.add(endDateStr);
            argTypesList.add(Types.VARCHAR);

            if (hospitalId > 0) {
                sql.append(" and (`hospital_id` = ? ) ");
                paramList.add(hospitalId);
                argTypesList.add(Types.INTEGER);
            }
            sql.append(" order by `pay_time` asc;");

            int size = argTypesList.size();
            int[] argTypes = new int[size];
            for (int i = 0; i < size; i++) {
                argTypes[i] = argTypesList.get(i);
            }
            SqlRowSet sqlRowSet = jdbcTemplate.queryForRowSet(sql.toString(), paramList.toArray(), argTypes);
            String[] fileHeader = new String[]{
                    "业务编码ID", "订单号", "支付流水号", "业务类型", "金额", "支付渠道标识", "支付渠道说明", "下单时间", "支付时间", "退款金额", "退款时间", "退款流水号", "医院ID", "医院名称"
            };

            StringBuffer stringBuffer = new StringBuffer();
            CSVPrinter csvPrinter = new CSVPrinter(stringBuffer, CSVFormat.DEFAULT.withHeader(fileHeader));
            SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String bizName = CommonBillTypeEnum.CONSULT_ORDER.getDisplayName();
            while (sqlRowSet.next()) {
                int payCh = PaymentChannelEnum.WeChat.getValue();
                String payChName = PaymentChannelEnum.valueOf(payCh).getDisplayName();
                int hospitalIdInt = Checker.getIntegerValue(sqlRowSet.getInt("hospital_id"));
                String hospitalName = Checker.getStringValue(sqlRowSet.getString("hospital_name"));
                csvPrinter.printRecord(sqlRowSet.getString("id"), sqlRowSet.getString("order_no"), sqlRowSet.getString("payment_no"),
                        bizName, sqlRowSet.getInt("amount"), payCh, payChName, sdf2.format(sqlRowSet.getDate("create_time")),
                        sdf2.format(sqlRowSet.getDate("pay_time")), 0, "", "", hospitalIdInt, hospitalName);
            }

            //退款账单
            sql = new StringBuilder(" Select `id`,`order_no`,`amount`,`payment_no`,`refund_status`,\n" +
                    " `refund_no`,`refund_callback_time`,`create_time`,`pay_time`, `hospital_id`, `hospital_name`\n" +
                    "  from `consult_order` where `refund_callback_time` like ? \n" +
                    " and `payment_status` = 2 and amount > 0 ");
            paramList = new ArrayList();
            argTypesList = new ArrayList();
            paramList.add(dayDate+"%");
            argTypesList.add(Types.VARCHAR);
            if (hospitalId > 0) {
                sql.append(" and (`hospital_id` = ? ) ");
                paramList.add(hospitalId);
                argTypesList.add(Types.INTEGER);
            }
            sql.append(" and refund_status = 1 order by `refund_callback_time` asc;");

            int sizeTwo = argTypesList.size();
            int[] argTypesTwo = new int[sizeTwo];
            for (int i = 0; i < sizeTwo; i++) {
                argTypesTwo[i] = argTypesList.get(i);
            }
            sqlRowSet = jdbcTemplate.queryForRowSet(sql.toString(), paramList.toArray(), argTypesTwo);

            while (sqlRowSet.next()) {
                int payCh = PaymentChannelEnum.WeChat.getValue();
                String payChName = PaymentChannelEnum.valueOf(payCh).getDisplayName();
                int hospitalIdInt = Checker.getIntegerValue(sqlRowSet.getInt("hospital_id"));
                String hospitalName = Checker.getStringValue(sqlRowSet.getString("hospital_name"));
                csvPrinter.printRecord(sqlRowSet.getString("id"), sqlRowSet.getString("order_no"), sqlRowSet.getString("payment_no"),
                        bizName, 0, payCh, payChName, sdf2.format(sqlRowSet.getDate("create_time")),
                        sdf2.format(sqlRowSet.getDate("pay_time")), sqlRowSet.getInt("amount"), sqlRowSet.getString("refund_callback_time"),
                        sqlRowSet.getString("refund_no"), hospitalIdInt, hospitalName);
            }

            csvPrinter.flush();
            csvData = stringBuffer.toString();
        } catch (Exception e) {
            logger.error("ConsultingService#getOrderBill(): {}", e.getMessage(), e);
        }
        return csvData;
    }
}
