package com.ywt.mg.services;

import com.ywt.mg.configs.ParameterConfigurer;
import com.ywt.mg.core.SqlHelper;
import com.ywt.mg.core.utils.Checker;
import com.ywt.mg.core.utils.DateUtil;
import com.ywt.mg.core.utils.FormatUtil;
import com.ywt.mg.domain.entities.OrderPayment;
import com.ywt.mg.domain.entities.OutpatientOrder;
import com.ywt.mg.domain.entities.RefundLog;
import com.ywt.mg.domain.entities.User;
import com.ywt.mg.domain.models.ConstantDef;
import com.ywt.mg.domain.models.ExcelDataMap;
import com.ywt.mg.domain.models.enums.*;
import com.ywt.mg.domain.models.pojo.ExcelCollectPojo;
import com.ywt.mg.params.outpatientOrder.QueryOutPatientOrderListRequest;
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.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class OutpatientOrderService {

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

    @Autowired
    private SqlHelper sqlHelper;

    @Autowired
    private ParameterConfigurer parameterConfigurer;

    @Autowired
    private AuthService authService;

    @Autowired
    private UserService userService;

    @Autowired
    private OrderPaymentService orderPaymentService;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private DownloadRecordService downloadRecordService;

    @Autowired
    private RefundLogService refundLogService;


    private List<OutpatientOrder> queryOutPatientOrderList(QueryOutPatientOrderListRequest request, int adminId) throws Exception {
        Map map = queryOutPatientOrderListCommonNew(request, adminId);

        String whereSql = (String) map.get(ConstantDef.KEY_WHERE_SQL);
        List paramList = (List) map.get(ConstantDef.KEY_PARAM_LIST);
        return sqlHelper.getListWithNoPage("*", whereSql, " id desc ", OutpatientOrder.class, paramList.toArray());
    }

    public Map<String, Object> queryOutPatientOrderListCommonNew(QueryOutPatientOrderListRequest request, int adminId) throws Exception {
        List<Object> paramList = new ArrayList<>();
        String whereSql = " ( 1=1 )";

        // 添加测试账号过滤
        String testAdminIds = parameterConfigurer.getTestAdminIds();
        String testDoctorCodes = parameterConfigurer.getTestDoctorCodes();
        String adminStr = "," + adminId + ",";
        String testAdminIdsStr = "," + testAdminIds + ",";

        // 不是测试账号
        if (!(testAdminIdsStr.contains(adminStr))) {
            String[] testDoctorIdsArr = testDoctorCodes.split(",");
            if (!Checker.isNone(testDoctorIdsArr)) {
                String sqlSubFrom = "";
                for (String doctorCode : testDoctorIdsArr) {
                    sqlSubFrom += "doctor_code != " + doctorCode + " and ";
                }
                sqlSubFrom = sqlSubFrom.substring(0, sqlSubFrom.lastIndexOf("and"));
                whereSql += String.format(" and ((%s) or doctor_code is null)", sqlSubFrom);
            }
        }
        String orderno = request.getOrderno();
        if (!Checker.isNone(orderno)) {
            whereSql += " and ( order_no like ?)";
            paramList.add("%" + orderno.trim() + "%");
        }
        String patientname = request.getPatientname();
        if (!Checker.isNull(patientname)) {
            whereSql += " and ( patient_name like ?)";
            paramList.add("%" + patientname.trim() + "%");
        }
        String userMobile = request.getUserMobile();
        if (!Checker.isNull(userMobile)) {
            int userId = userService.getUserIdByMobile(userMobile);
            if (userId > 0) {
                whereSql += " and ( user_id = ?)";
                paramList.add(userId);
            } else {
                whereSql += " and ( user_id = -1)";
            }
        }
        String doctorname = request.getDoctorname();
        if (!Checker.isNull(doctorname)) {
            whereSql += " and ( doctor_name like ?)";
            paramList.add("%" + doctorname.trim() + "%");
        }
        String deptname = request.getDeptname();
        if (!Checker.isNull(deptname)) {
            whereSql += " and ( dept_name like ?)";
            paramList.add("%" + deptname.trim() + "%");
        }
        String hospitalname = request.getHospitalname();
        if (!Checker.isNull(hospitalname)) {
            whereSql += " and ( hospital_name like ?)";
            paramList.add("%" + hospitalname.trim() + "%");
        }

        //门诊缴费状态
        String outpatientstatus = request.getOutpatientstatus();
        if (!Checker.isNull(outpatientstatus)) {
            int status = Integer.parseInt(outpatientstatus);
            whereSql += " and ( outpatient_status = ?  )";
            paramList.add(status);
        } else {
            whereSql += " and ( outpatient_status > ?  )";
            paramList.add(OutpatientStatusEnum.PENDING.getValue());
        }

        //支付状态（0-待支付，1-支付处理中，2-支付成功，3-支付失败）
        String paymentstatus = request.getPaymentstatus();
        if (!Checker.isNull(paymentstatus)) {
            whereSql += " and ( payment_status =  ?  )";
            paramList.add(Integer.parseInt(paymentstatus));
        }

        String terminal = request.getTerminal();
        if (!Checker.isNull(terminal)) {
            int terminalId = Integer.parseInt(terminal);
            whereSql += " and ( terminal = ? )";
            paramList.add(terminalId);
        }

        //express   1-可以快递   0-不可以
        String express = request.getExpress();
        if (!Checker.isNull(express)) {
            int expressInt = Integer.parseInt(express);
            if (expressInt == 1) {
                whereSql += " and ( express =  ? )";
                paramList.add(expressInt);
            } else {
                whereSql += " and ( express =  ? or express is null)";
                paramList.add(expressInt);
            }
        }

        String formatDate = "yyyy-MM-dd";
        SimpleDateFormat format = new SimpleDateFormat(formatDate);

        //下单时间
        String createEndTime = request.getCreateEndTime();
        String createStartTime = request.getCreateStartTime();
        if (!Checker.isNull(createEndTime)) {
            whereSql += " and ( create_time < ? )";
            Date date = format.parse(createEndTime);

            // 把日期往后增加一天.整数往后推,负数往前移动
            Calendar calendar = new GregorianCalendar();
            calendar.setTime(date);
            calendar.add(Calendar.DATE, 1);
            // 这个时间就是日期往后推一天的结果
            date = calendar.getTime();

            paramList.add(date);
        }

        if (!Checker.isNull(createStartTime)) {
            whereSql += " and ( create_time >= ?)";
            Date date = format.parse(createStartTime);
            paramList.add(date);
        }

        //支付时间
        String payEndTime = request.getPayEndTime();
        String payStartTime = request.getPayStartTime();
        if (!Checker.isNull(payEndTime)) {
            whereSql += " and ( pay_time < ? )";
            Date date = format.parse(payEndTime);

            // 把日期往后增加一天.整数往后推,负数往前移动
            Calendar calendar = new GregorianCalendar();
            calendar.setTime(date);
            calendar.add(Calendar.DATE, 1);
            // 这个时间就是日期往后推一天的结果
            date = calendar.getTime();

            paramList.add(date);
        }

        if (!Checker.isNull(payStartTime)) {
            whereSql += " and ( pay_time >= ?)";
            Date date = format.parse(payStartTime);
            paramList.add(date);
        }
        int hospitalId = request.getHospitalId();
        if (hospitalId > 0) {
            whereSql += " and ( hospital_id = ?)";
            paramList.add(hospitalId);
        }
        // 对账时间搜索
        String billEndTime = request.getBillEndTime();
        String billStartTime = request.getBillStartTime();
        if (!Checker.isNull(billEndTime)) {
            whereSql += " and ( pay_time < ? or refund_time < ?)";
            Date date = format.parse(billEndTime);
            //把日期往后增加一天.整数往后推,负数往前移动
            Calendar calendar = new GregorianCalendar();
            calendar.setTime(date);
            calendar.add(calendar.DATE, 1);
            date = calendar.getTime();   //这个时间就是日期往后推一天的结果

            paramList.add(date);
            paramList.add(date);
        }
        if (!Checker.isNull(billStartTime)) {
            whereSql += " and ( pay_time >= ? or refund_time >= ?)";
            Date date = format.parse(billStartTime);
            paramList.add(date);
            paramList.add(date);
        }

        String transactionId = request.getTransactionId();
        try {
            // 处理交易流水号，考虑到性能，直接采用全匹配到方式
            if (!Checker.isNull(transactionId)) {
                OrderPayment orderPayment = orderPaymentService.getOrderPaymentByTransactionId(transactionId);
                if (!Checker.isNone(orderPayment)) {
                    whereSql += " and ( order_id = ? )";
                    paramList.add(orderPayment.getOrderId());
                } else {
                    whereSql += " and ( order_id = -1 )";
                }
            }
        } catch (Exception e) {
            logger.error("OutpatientOrderService#queryOutPatientOrderListCommonNew(transactionId={} ):\n {} ", transactionId, e.getMessage(), e);
        }

        whereSql += " and ( deleted = 0 )";
        Map map = new HashMap();
        map.put(ConstantDef.KEY_WHERE_SQL, whereSql);
        map.put(ConstantDef.KEY_PARAM_LIST, paramList);
        return map;
    }

    public void downloadOutPatientOrderListCommon(int downloadRecordId, String fileName, QueryOutPatientOrderListRequest request,  int adminId) {
        try {
            boolean isAdmin = request.isAdmin();
            String col0 = "订单号";
            String col1 = "支付流水号";
            String col2 = "交易流水号";
            String col3 = "患者姓名";
            String col4 = "患者手机号";
            String col5 = "诊疗卡";
            String col6 = "医生姓名";
            String col7 = "科室";
            String col8 = "医院";
            String col9 = "来源";
            String col10 = "金额";
            String col11 = "配送";
            String col12 = "订单状态";
            String col13 = "支付状态";
            String col14 = "创建时间";
            String col15 = "支付时间";
            String[] columns = new String[]{col0, col1, col2, col3, col4, col5, col6, col7, col8, col9, col10,
                    col11, col12, col13, col14, col15};
            if (isAdmin == false) {
                columns = new String[]{col0, col1, col2, col3, col4, col5, col6, col7, col9, col10,
                        col12, col13, col14, col15};
            }

            List<OutpatientOrder> list = queryOutPatientOrderList(request, adminId);
            List<User> userList = getUserListByOutpatientOrderViewList(list, list.size());
            List<OrderPayment> orderPaymentList = orderPaymentService.getOrderPaymentListByOutPatientOrderList(list);
            int payTotal = 0;
            ExcelDataMap map = new ExcelDataMap(columns);
            if (!Checker.isNone(list)) {
                for (OutpatientOrder p : list) {
                    String orderNoValue = Checker.getStringValue(p.getOrderNo());
                    String paymentNoValue = Checker.getStringValue(p.getPaymentNo());
                    String patientNameValue = p.getPatientName();
                    String mobileValue = getUserMobile(userList, Checker.getIntegerValue(p.getUserId()));
                    String hisPatientId = p.getHisPatientId();
                    String doctorNameValue = p.getDoctorName();
                    String deptNameValue = p.getDeptName();
                    String hospitalNameValue = p.getHospitalName();
                    String total = FormatUtil.decimalFormat(p.getTotal() / 100.0);
                    String expressStr = getOutpatientExpressStr(Checker.getIntegerValue(p.getExpress()));

                    int outpatientStatusInt = Checker.getIntegerValue(p.getOutpatientStatus());
                    String outpatientStatusStr = OutpatientStatusEnum.valueOf(outpatientStatusInt).getDisplayName();

                    int paymentStatusInt = Checker.getIntegerValue(p.getPaymentStatus());
                    String paymentStatusStr = PaymentStatusEnum.getPaymentStatus(paymentStatusInt).getDisplayName();
                    String createTimeValue = FormatUtil.createTimeFormatList(p.getCreateTime());
                    String payTimeValue = FormatUtil.createTimeFormatList(p.getPayTime());
                    String terminal = "";
                    if (!Checker.isNone(p.getTerminal())) {
                        terminal = TerminalEnum.valueOf(p.getTerminal()).getDisplayName();
                    }
                    // 交易流水号
                    String transactionId = orderPaymentService.getTransactionIdByOrderId(orderPaymentList, Checker.getIntegerValue(p.getOrderId()));
//
//                    String[] bodyStr = new String[]{orderNoValue, paymentNoValue, transactionId, patientNameValue, mobileValue, hisPatientId, doctorNameValue, deptNameValue,
//                            hospitalNameValue, terminal, total, expressStr, outpatientStatusStr, paymentStatusStr, createTimeValue, payTimeValue};
//                    if (isAdmin == false) {
//                        bodyStr = new String[]{orderNoValue, paymentNoValue, transactionId, patientNameValue, mobileValue, hisPatientId, doctorNameValue, deptNameValue, terminal,
//                                total, outpatientStatusStr, paymentStatusStr, createTimeValue, payTimeValue};
//                    }
                    if (Checker.getIntegerValue(p.getPaymentStatus()) == PaymentStatusEnum.Success.getValue()) {
                        payTotal += Checker.getIntegerValue(p.getTotal());
                    }

                    if (isAdmin == false) {
                        map.getStringListSafely(col0).add(orderNoValue);
                        map.getStringListSafely(col1).add(paymentNoValue);
                        map.getStringListSafely(col2).add(transactionId);
                        map.getStringListSafely(col3).add(patientNameValue);
                        map.getStringListSafely(col4).add(mobileValue);
                        map.getStringListSafely(col5).add(hisPatientId);
                        map.getStringListSafely(col6).add(doctorNameValue);
                        map.getStringListSafely(col7).add(deptNameValue);
//                        map.getStringListSafely(col8).add(hospitalNameValue);
                        map.getStringListSafely(col9).add(terminal);
                        map.getStringListSafely(col10).add(total);
//                        map.getStringListSafely(col11).add(expressStr);
                        map.getStringListSafely(col12).add(outpatientStatusStr);
                        map.getStringListSafely(col13).add(paymentStatusStr);
                        map.getStringListSafely(col14).add(createTimeValue);
                        map.getStringListSafely(col15).add(payTimeValue);
                    } else {
                        map.getStringListSafely(col0).add(orderNoValue);
                        map.getStringListSafely(col1).add(paymentNoValue);
                        map.getStringListSafely(col2).add(transactionId);
                        map.getStringListSafely(col3).add(patientNameValue);
                        map.getStringListSafely(col4).add(mobileValue);
                        map.getStringListSafely(col5).add(hisPatientId);
                        map.getStringListSafely(col6).add(doctorNameValue);
                        map.getStringListSafely(col7).add(deptNameValue);
                        map.getStringListSafely(col8).add(hospitalNameValue);
                        map.getStringListSafely(col9).add(terminal);
                        map.getStringListSafely(col10).add(total);
                        map.getStringListSafely(col11).add(expressStr);
                        map.getStringListSafely(col12).add(outpatientStatusStr);
                        map.getStringListSafely(col13).add(paymentStatusStr);
                        map.getStringListSafely(col14).add(createTimeValue);
                        map.getStringListSafely(col15).add(payTimeValue);
                    }
                }
            }
            int size = list.size();
            List<ExcelCollectPojo> itemList = getStatisticsData(size, payTotal);
            downloadRecordService.createFileAndUploadOssAndSaveToDataBase(fileName, downloadRecordId, map, itemList);
        } catch (Exception e) {
            logger.error("/outPatient/downloadOutPatientOrderList(): {}", e.getMessage(), e);
            e.printStackTrace();
        }

    }

    public String getUserMobile(List<User> userList, int userId) {
        if (userId == 0) {
            return "";
        }
        if (!Checker.isNone(userList)) {
            User user = userList.stream().filter(p -> p.getId().intValue() == userId).findFirst().orElse(null);
            if (!Checker.isNone(user)) {
                return Checker.getStringValue(user.getMobile());
            }
        }
        return "";
    }


    public List<User> getUserListByOutpatientOrderViewList(List<OutpatientOrder> offList, int size) {
        String userIds = getUserIdsByList(offList);
        if (!Checker.isNone(userIds)) {
            String sql = "select * from user where is_deleted = 0 and (" + userIds + ") limit " + size + ";";
            return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class));
        }
        return null;
    }

    public String getUserIdsByList(List<OutpatientOrder> viewList) {
        String userIds = "";
        if (!Checker.isNone(viewList)) {
            for (OutpatientOrder view : viewList) {
                if (Checker.getIntegerValue(view.getUserId()) != 0) {
                    userIds += " id = " + view.getUserId() + " or";
                }
            }
            if (userIds.length() > 0) {
                userIds = userIds.substring(0, userIds.length() - 2);
            }
        }
        return userIds;
    }

    public String getOutpatientExpressStr(int express) {
        if (express == OutpatientExpressEnum.YES.getValue()) {
            return OutpatientExpressEnum.YES.getDisplayName();
        }
        if (express == OutpatientExpressEnum.NO.getValue()) {
            return OutpatientExpressEnum.NO.getDisplayName();
        }
        return "";
    }

    /**
     * 获取统计数据
     *
     * @param size     隔行
     * @param payTotal 总金额
     * @return {@link List<ExcelCollectPojo> }
     */
    private List<ExcelCollectPojo> getStatisticsData(int size, int payTotal) {
        int startRows = size + 3;
        int startColumn = 3;

        List<ExcelCollectPojo> customExcelItemList = new ArrayList<>();
        customExcelItemList.add(new ExcelCollectPojo(startColumn + 1, startRows + 1, new String[]{"支付总额", FormatUtil.intShrink100ToStr(payTotal)}));
        return customExcelItemList;
    }

    public void downloadOutPatientOrderBillListNew(int downloadRecordId, String fileName,  QueryOutPatientOrderListRequest request, int adminId){
        try {
                    String col0 = "交易类型*";
                    String col1 = "系统参考号*";
                    String col2 = "交易金额*";
                    String col3 =  "交易日期*";
                    String col4 = "订单号";
                    String col5 = "类型";
            String[] columns = new String[]{col0, col1, col2, col3, col4, col5};
            //给第二行设置背景、字体颜色、对齐方式等等;
            // 只搜索已支付的订单
            request.setPaymentstatus(PaymentStatusEnum.Success.getValue() + "");
            List<OutpatientOrder> outpatientOrderList = queryOutPatientOrderList(request, adminId);
            ExcelDataMap map = new ExcelDataMap(columns);
            if (!Checker.isNone(outpatientOrderList)) {
                // 得到支付的记录日志（需要从 order_payment 获取 transaction_id 字段）
                List<OrderPayment> orderPaymentList = orderPaymentService.getOrderPaymentListByOutPatientOrderList(outpatientOrderList);
                Date billStartTime = DateUtil.stringToDate(request.getBillStartTime() + ConstantDef.BILL_TIME_START_FORMAT);
                Date billEndTime = DateUtil.stringToDate(request.getBillEndTime() + ConstantDef.BILL_TIME_END_FORMAT);
                for (OutpatientOrder p : outpatientOrderList){
                    if (!Checker.isNone(p) && Checker.getIntegerValue(p.getPaymentStatus()) == PaymentStatusEnum.Success.getValue()
                            && !Checker.isNone(p.getPayTime())) {
                        Date paymentTime = Checker.getDateValue(p.getPayTime());
                        if (!Checker.isNone(paymentTime) && paymentTime.after(billStartTime) && paymentTime.before(billEndTime)) {
                            String type = ConstantDef.BILL_PAYMENT_STR;
                            // 交易流水号
                            String transactionId = orderPaymentService.getTransactionIdByOrderId(orderPaymentList, Checker.getIntegerValue(p.getOrderId()));
                            // 交易金额
                            int total = Checker.getIntegerValue(p.getTotal());
                            String totalStr = FormatUtil.intShrink100ToStr(total);
                            // 交易时间
                            String paymentTimeStr = FormatUtil.createTimeFormatDetail(p.getPayTime());
                            // 订单号
                            String orderNo = Checker.getStringValue(p.getOrderNo());
                            // 类型
                            String typeStr = "门诊缴费";
//                            String[] bodyStr = {type, transactionId, totalStr, paymentTimeStr, orderNo, typeStr};
                            map.getStringListSafely(col0).add(type);
                            map.getStringListSafely(col1).add(transactionId);
                            map.getStringListSafely(col2).add(totalStr);
                            map.getStringListSafely(col3).add(paymentTimeStr);
                            map.getStringListSafely(col4).add(orderNo);
                            map.getStringListSafely(col5).add(typeStr);
                        }
                    }
                }
                // 得到退款的记录日志（需要从 refund_log 获取 refund_id 字段）
                List<RefundLog> refundLogList = refundLogService.getRefundLogListByOutPatientOrderList(outpatientOrderList);
                List<OutpatientOrder> refundPrescriptionInfoList = getRefundOutpatientOrderList(outpatientOrderList);
                for (OutpatientOrder p : refundPrescriptionInfoList) {
                    if (!Checker.isNone(p) && Checker.getIntegerValue(p.getRefundStatus()) == RefundStatusEnum.SUCCESS.getValue()) {
                        // "交易类型*", "系统参考号*", "交易金额*", "交易日期*", "订单号", "类型"
                        Date refundTime = Checker.getDateValue(p.getRefundTime());
                        if (!Checker.isNone(refundTime) && refundTime.after(billStartTime) && refundTime.before(billEndTime)) {
                            String type = ConstantDef.BILL_REFUND_STR;
                            String transactionId = refundLogService.getRefundIdByRefundNo(refundLogList, p.getRefundNo());

                            // 交易金额
                            int total = Checker.getIntegerValue(p.getTotal());
                            String totalStr = FormatUtil.intShrink100ToStr(total);
                            // 交易时间
                            String refundTimeStr = FormatUtil.createTimeFormatDetail(p.getRefundTime());
                            // 订单号
                            String orderNo = Checker.getStringValue(p.getOrderNo());
                            // 类型
                            String typeName = "门诊缴费";
                            map.getStringListSafely(col0).add(type);
                            map.getStringListSafely(col1).add(transactionId);
                            map.getStringListSafely(col2).add(totalStr);
                            map.getStringListSafely(col3).add(refundTimeStr);
                            map.getStringListSafely(col4).add(orderNo);
                            map.getStringListSafely(col5).add(typeName);
//                            String[] bodyStr = {type, transactionId, totalStr, refundTimeStr, orderNo, typeName};
                        }
                    }
                }
            }
            int size = outpatientOrderList.size();
            List<ExcelCollectPojo> itemList = new ArrayList<>();
            downloadRecordService.createFileAndUploadOssAndSaveToDataBase(fileName, downloadRecordId, map, itemList);
        } catch (Exception e) {
            logger.error("/registeredOrder/downloadRegisteredOrderList: {}", e.getMessage(), e);
            e.printStackTrace();
        }
    }

    private List<OutpatientOrder> getRefundOutpatientOrderList(List<OutpatientOrder> list) {
        if (!Checker.isNone(list)) {
            return list.stream().filter(p -> Checker.getIntegerValue(p.getRefundStatus()) == RefundStatusEnum.SUCCESS.getValue()).collect(Collectors.toList());
        }
        return new ArrayList<>();
    }
}
