package com.ywt.alipaympapi.service.impl;

import com.google.protobuf.StringValue;
import com.ywt.alipaympapi.core.utils.*;
import com.ywt.alipaympapi.models.Constants;
import com.ywt.alipaympapi.models.enums.PaymentChannelEnum;
import com.ywt.alipaympapi.service.services.DoctorSrv;
import com.ywt.alipaympapi.service.services.SystemSrv;
import com.ywt.core.exception.AppMessageException;
import com.ywt.gapi.ResultCode;
import com.ywt.gapi.system.Dept;
import com.ywt.gapi.system.SystemServiceGrpc;
import com.ywt.gapi.taihe.register.CreateRegisteredRequest;
import com.ywt.gapi.taihe.register.CreateRegisteredResponse;
import com.ywt.gapi.taihe.register.TaiheRegisterServiceGrpc;
import com.ywt.gapi.third.taihe.GetScheduleListRequest;
import com.ywt.gapi.third.taihe.GetScheduleListResponse;
import com.ywt.gapi.third.taihe.Schedule;
import com.ywt.gapi.third.taihe.TaiheServiceGrpc;
import com.ywt.gapi.user.DeptScheduleDoctor;
import com.ywt.gapi.user.DoctorServiceGrpc;
import com.ywt.gapi.user.GetDoctorByHisCodeRequest;
import com.ywt.gapi.user.GetDoctorByHisCodeResponse;
import com.ywt.request.nucleic.NucleicItemListRequest;
import com.ywt.request.nucleic.NucleicOrderConfirmRequest;
import com.ywt.request.nucleic.NucleicQuestionnaireRequest;
import com.ywt.request.nucleic.NucleicQuestionnaireResultRequest;
import com.ywt.request.nucleic.NucleicTimeListRequest;
import com.ywt.response.nucleic.NucleicItemResponseData;
import com.ywt.response.nucleic.NucleicOrderConfirmResponseData;
import com.ywt.response.nucleic.NucleicQuestionnaireResponseData;
import com.ywt.response.nucleic.NucleicQuestionnaireResultResponseData;
import com.ywt.response.nucleic.NucleicTimeListResponseData;
import com.ywt.alipaympapi.service.NucleicService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.JedisCommands;

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

/**
 * @author
 */
@Slf4j
@Service
public class NucleicServiceImpl implements NucleicService {

    @Autowired
    private SystemServiceGrpc.SystemServiceBlockingStub systemServiceBlockingStub;

    @Autowired
    private JedisCommands jedisCommands;

    @Autowired
    private SystemSrv systemSrv;

    @Autowired
    private DoctorSrv doctorSrv;

    @Autowired
    private TaiheServiceGrpc.TaiheServiceBlockingStub taiheServiceBlockingStub;

    @Autowired
    private DoctorServiceGrpc.DoctorServiceBlockingStub doctorServiceBlockingStub;

    @Autowired
    private TaiheRegisterServiceGrpc.TaiheRegisterServiceBlockingStub taiheRegisterServiceBlockingStub;


    @Override
    public List<NucleicItemResponseData> itemList(NucleicItemListRequest request) throws Exception {

        int hospitalId = BizUtil.getCurrentHospitalId();
        if (Checker.isNone(request.getDeptCode())) {
            throw new AppMessageException("deptCode不能为空");
        }
        String doctorCode = "";
        String serviceCode = "";
        List<NucleicItemResponseData> list = new ArrayList<>();
        list = getScheduleListCommon(hospitalId, request.getDeptCode(), doctorCode, serviceCode, -1, -1);
        return list;
    }

    @Override
    public NucleicTimeListResponseData testTimeList(NucleicTimeListRequest request) {
        return null;
    }

    @Override
    public NucleicQuestionnaireResponseData questionnaire(NucleicQuestionnaireRequest request) {
        return null;
    }

    @Override
    public NucleicQuestionnaireResultResponseData questionnaireResult(NucleicQuestionnaireResultRequest request) {
        return null;
    }

    @Override
    public NucleicOrderConfirmResponseData orderConfirm(NucleicOrderConfirmRequest request) throws Exception {
        int hospitalId = BizUtil.getCurrentHospitalId();
        String deptCode = Checker.getStringValue(request.getDeptCode());
        String deptName = Checker.getStringValue(request.getDeptName());
        if (Checker.isNone(deptCode) || Checker.isNone(deptName)) {
            throw new AppMessageException("科室不存在");
        }
        String doctorCode = Checker.getStringValue(request.getDoctorCode());
        String doctorName = Checker.getStringValue(request.getDoctorName());
        if (Checker.isNone(doctorCode) || Checker.isNone(doctorName)) {
            throw new AppMessageException("医生不存在");
        }
        Date date = new Date();
        if (!StringHelper.isNullOrEmpty(request.getRegisterDate())) {
            Date rDate = DateUtil.parseDate(request.getRegisterDate(), DateUtil.DADE_FROMAT_YMD);
            if (rDate != null) {
                date = rDate;
            }
        }

        int deptId = 0;
        switch (hospitalId) {
            case Constants.TAIHE_HOSPITAL_ID:
                deptId = Constants.NUCLEIC_DEPT_ID_TAIHE;
                break;
            case Constants.HOSPITAL_ID_NFYYBYFY:
                if (request.getDeptCode().equals(Constants.NUCLEIC_DEPT_CODE_NFYYBYFY_HS)) {
                    deptId = Constants.NUCLEIC_DEPT_ID_NFYYBYFY_HS;
                } else {
                    deptId = Constants.NUCLEIC_DEPT_ID_NFYYBYFY_SH;
                }
                break;
            default:
                break;
        }
        CheckUtil.ensureLargerThanZero(deptId, "核酸科室 id 配置有误");

        int paymentChannel = request.getFee() > 0
                ? PaymentChannelEnum.ALI_PAY.getValue()
                : PaymentChannelEnum.FREE.getValue();
        String startTime = Checker.getStringValue(request.getStartTime());
        String endTime = Checker.getStringValue(request.getEndTime());
        int userId = ContextHelper.getCurrentUserIdWrapped();
        int source = ContextHelper.getCurrentTerminalWrapped();
        int subHospitalId = Checker.parseInt(Checker.getStringValue(request.getSubHospitalId(), "0"));
        CreateRegisteredRequest req = CreateRegisteredRequest.newBuilder()
                .setDeptCode(deptCode)
                .setDeptName(deptName)
                .setDoctorCode(doctorCode)
                .setDoctorName(doctorName)
                .setTotal(Checker.getIntegerValue(request.getFee()))
                .setRegisteredFee(Checker.getIntegerValue(request.getFee()))
                .setMedicalFee(0)
                .setRegisteredDate(date.getTime())
                .setStartTime(startTime)
                .setEndTime(endTime)
                .setUserId(userId)
                .setMedicalCardId(request.getMedicalId())
                .setScheduleItemCode(request.getNucleicItemId())
                .setPaymentChannel(paymentChannel)
                .setSource(source)
                .setPeriod(request.getDatePeriod())
                .setDoctorTitle("")
                .setDeptId(Checker.getIntegerValue(deptId))
                .setLockQueueNo("")
                .setAvailableNumStr(request.getAvailableNumStr())
                .setHospitalId(hospitalId)
                .setSubHospitalId(subHospitalId)
                .build();
        CreateRegisteredResponse res = taiheRegisterServiceBlockingStub.createRegistered(req);

        if (res.getCode() != ResultCode.SUCCEED_VALUE) {
            //预约失败
            throw new AppMessageException(res.getMsg());
        }
        //非互联网医院名医诊区挂号
        NucleicOrderConfirmResponseData data = new NucleicOrderConfirmResponseData();
        data.setAmount(String.format("%.2f", request.getFee() / 100d));
        data.setOrderId(String.valueOf(res.getOrderId()));
        data.setOrderNo(res.getOrderNo());
        return data;
    }


    private List<NucleicItemResponseData> getScheduleListCommon(int hospitalId, String deptCode, String doctorCode,
                                                                String serviceCode, int startOffset, int endOffset) throws AppMessageException {
        //支付宝核酸
        String redisKeyPattern = "ALI_HS_SCHEDULE_LIST_%s_%s_%d_%s";
        String key = String.format(redisKeyPattern, deptCode, doctorCode, hospitalId, serviceCode);
        if (startOffset >= 0 && endOffset >= 0) {
            redisKeyPattern = "ALI_HS_SCHEDULE_LIST_%s_%s_%d_%s_%d_%d";
            key = String.format(redisKeyPattern, deptCode, doctorCode, hospitalId, serviceCode, startOffset, endOffset);
        }
        String value = jedisCommands.get(key);
        if (!StringHelper.isNullOrWhiteSpace(value)) {
            List<NucleicItemResponseData> lss  = JsonSerializer.from(value, List.class);
            if (lss != null) {
                return lss;
            }
        }

        List<Dept> deptList = systemSrv.getDeptListByHospitalId(hospitalId);
        if (deptList == null || deptList.size() == 0) {
            throw new AppMessageException(String.format("无法获取科室数据(%d)", hospitalId));
        }
        List<Dept> tmpDeptList = deptList.stream().filter(p -> p.getDeptCode().equals(deptCode)).collect(Collectors.toList());
        if (tmpDeptList.size() == 0) {
            throw new AppMessageException("暂无出诊信息");
        }
        Dept secDept = tmpDeptList.get(0);
        tmpDeptList = deptList.stream().filter(p -> p.getDeptId() == secDept.getParentId()).collect(Collectors.toList());
        if (tmpDeptList.size() == 0) {
            throw new AppMessageException("暂无出诊信息");
        }

        Map<String, Object> map = new HashMap<>();
        map.put("hospitalId", hospitalId);
        map.put("hospitalName", BizUtil.getHospitalNameByIdSimply(hospitalId));
        map.put("deptCode", deptCode);
        map.put("deptName", secDept.getDeptName());

        List<DeptScheduleDoctor> doctorList = doctorSrv.getDeptScheduleDoctorListFromCache();
//        doctorList = doctorList.stream().filter(p -> p.getDeptCode().equals(deptCode)).collect(Collectors.toList());

        // 批量日期查询 HIS 接口
        boolean isTaihe = hospitalId == Constants.TAIHE_HOSPITAL_ID;
        if (startOffset < 0 || endOffset < 0) {
            startOffset = isTaihe ? 1 : 0;
            endOffset = isTaihe ? 9 : 7;
        }
        List<NucleicItemResponseData> lst = getConvertedScheduleList(hospitalId, startOffset, endOffset, deptCode,
                doctorCode, serviceCode);
        jedisCommands.set(key, JsonSerializer.toJson(lst));
        jedisCommands.expire(key, 3 * 60);
        return lst;
    }


    private List<NucleicItemResponseData> getConvertedScheduleList(int hospitalId, int startOffset, int endOffset, String deptCode,
                                                                   String doctorCode, String serviceCode) {
        Calendar calendar = Calendar.getInstance();
        if (startOffset > 0) {
            calendar.add(Calendar.DATE, startOffset);
        }
        String startDate = DateUtil.formatDate(calendar.getTime(), "yyyy-MM-dd"); //日期
        calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, endOffset);
        String endDate = DateUtil.formatDate(calendar.getTime(), "yyyy-MM-dd"); //日期

        GetScheduleListRequest getScheduleListRequest = GetScheduleListRequest.newBuilder()
                .setDeptCode(deptCode)
                .setDoctorCode(doctorCode)
                .setServiceDate(startDate)
                .setServiceEndDate(endDate)
                .setHospitalId(hospitalId)
                .setServiceCode(serviceCode)
                .build();
        GetScheduleListResponse getScheduleListResponse = taiheServiceBlockingStub.getScheduleList(getScheduleListRequest);
        List<Schedule> scheduleList;
        Date date = getCurrentDate();
        if (getScheduleListResponse.getCode() == ResultCode.SUCCEED_VALUE) {
            scheduleList = getScheduleListResponse.getSchedulesList();
            scheduleList = scheduleList.stream()
                    .filter(p -> date.compareTo(DateUtil.parseDate(p.getServiceDate() + " " + p.getEndTime(), "yyyy-MM-dd HH:mm")) < 0)
                    .sorted(Comparator.comparing(Schedule::getServiceDate).thenComparing(Schedule::getDatePeriod)).collect(Collectors.toList());

        } else {
            scheduleList = new LinkedList<>();
        }

        return convertToScheduleMap(scheduleList, hospitalId);

    }

    /**
     * 排班记录转为Map
     */
    private List<NucleicItemResponseData> convertToScheduleMap(List<Schedule> scheduleList, int hospitalId) {
        List<NucleicItemResponseData> list = new ArrayList<>();

        List<Map<String, Object>> forenoonList = new LinkedList<>();
        List<Map<String, Object>> afternoonList = new LinkedList<>();
        List<Map<String, Object>> nightList = new LinkedList<>();
        List<Map<String, Object>> afterMidnightList = new LinkedList<>();   // 下半夜排班
        List<Map<String, Object>> midnoonList = new ArrayList<>();          //午间排班记录
        GetDoctorByHisCodeResponse getDoctorByHisCodeResponse;
        String avatar;

        int doctorId;
        boolean hasScheduling = scheduleList.size() > 0;    //当期日期是否有排班


        for (Schedule s : scheduleList) {


            doctorId = 0;
            avatar = Constants.DOCTOR_AVATAR_URL;
            getDoctorByHisCodeResponse = getDoctorByHisCode(s.getDoctorCode(), hospitalId);

            if (getDoctorByHisCodeResponse.getResult().getCode() == ResultCode.SUCCEED) {
                if (!StringHelper.isNullOrWhiteSpace(getDoctorByHisCodeResponse.getAvatar())) {
                    avatar = getDoctorByHisCodeResponse.getAvatar();
                }

                doctorId = getDoctorByHisCodeResponse.getDoctorId();
            }
            if (doctorId <= 0) {
                continue;
            }
            NucleicItemResponseData data = new NucleicItemResponseData();
            Map<String, Object> scheduleMap = new HashMap<>();
            data.setNucleicItemId(s.getScheduleItemCode());
            Integer fee = s.getFee();
            data.setFee(Checker.getIntegerValue(fee));
            String feeStr = fee.toString();
            data.setNucleicItemFee(feeStr);
            data.setNucleicItemDesc(Checker.getStringValue(s.getServiceDate()) + "  " + Checker.getStringValue(s.getDatePeriodName()));
            data.setNucleicDate(DateUtil.stringToDate(s.getServiceDate(), "yyyy-MM-dd"));
            data.setNucleicItemName(Checker.getStringValue(s.getDoctorName()));
            data.setStartTime(Checker.getStringValue(s.getStartTime()));
            data.setEndTime(Checker.getStringValue(s.getEndTime()));
            data.setDatePeriod(s.getDatePeriod());
            data.setDeptCode(Checker.getStringValue(s.getDeptCode()));
            data.setAvailableNumStr(Checker.getStringValue(s.getAvailableNumStr()));
            data.setDeptName(Checker.getStringValue(s.getDeptName()));
            data.setDoctorCode(Checker.getStringValue(s.getDoctorCode()));
            data.setDoctorName(Checker.getStringValue(s.getDoctorName()));
            data.setNucleicItemId(Checker.getStringValue(s.getScheduleItemCode()));
            list.add(data);
        }
        return list;
    }


    private GetDoctorByHisCodeResponse getDoctorByHisCode(String doctorCode, int hospitalId) {
        GetDoctorByHisCodeRequest getDoctorByHisCodeRequest = GetDoctorByHisCodeRequest.newBuilder()
                .setHospitalId(hospitalId)
                .setHisCode(doctorCode)
                .build();
        return doctorServiceBlockingStub.getDoctorByHisCode(getDoctorByHisCodeRequest);
    }

    private Date getCurrentDate() {
        try {
            String value = DateUtil.formatDate(new Date(), DateUtil.DADE_FROMAT_YMDHMS);
            return DateUtil.parseDate(value, DateUtil.DADE_FROMAT_YMDHMS);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
