package com.yihu.wlyy.service.app.sign;

import com.yihu.wlyy.entity.doctor.profile.Doctor;
import com.yihu.wlyy.entity.organization.Hospital;
import com.yihu.wlyy.entity.patient.Patient;
import com.yihu.wlyy.entity.patient.SignFamily;
import com.yihu.wlyy.repository.doctor.DoctorDao;
import com.yihu.wlyy.repository.organization.HospitalDao;
import com.yihu.wlyy.repository.patient.PatientDao;
import com.yihu.wlyy.repository.patient.SignFamilyDao;
import com.yihu.wlyy.service.BaseService;
import com.yihu.wlyy.service.common.SMSService;
import com.yihu.wlyy.task.PushMsgTask;
import com.yihu.wlyy.util.DateUtil;
import com.yihu.wlyy.util.SendP2PUtil;
import com.yihu.wlyy.wechat.util.WeiXinAccessTokenUtils;
import org.apache.commons.collections.FastHashMap;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 缴费提醒服务
 * <p>
 * Created by lyr on 2016/10/24.
 */
@Service
public class PatientRemindService extends BaseService {

    @Autowired
    SignFamilyDao signFamilyDao;
    @Autowired
    DoctorDao doctorDao;
    @Autowired
    PatientDao patientDao;
    @Autowired
    HospitalDao hospitalDao;
    @Autowired
    SMSService smsService;
    @Autowired
    StringRedisTemplate redisTemplate;
    @Autowired
    WeiXinAccessTokenUtils tokenUtils;
    @Autowired
    JdbcTemplate jdbcTemplate;

    /**
     * 缴费提醒
     *
     * @param doctor 医生
     * @throws Exception
     */
    @Async
    public void remindPatientExpensesAll(String doctor) throws Exception {
        try {
            Doctor doc = doctorDao.findByCode(doctor);
            if (doc == null) {
                throw new Exception("doctor info can not find");
            }

            Hospital hos = hospitalDao.findByCode(doc.getHospital());
            if (hos == null) {
                throw new Exception("hospital info can not find");
            }

            RemindAll(doc, hos);
            redisTemplate.opsForValue().set("expenses:remind:doctor:" + doctor, "0");
            redisTemplate.expire("expenses:remind:doctor:" + doctor, 10, TimeUnit.MINUTES);
        } catch (Exception e) {
            redisTemplate.opsForValue().set("expenses:remind:doctor:" + doctor, "0");
            redisTemplate.expire("expenses:remind:doctor:" + doctor, 10, TimeUnit.MINUTES);
            e.printStackTrace();
        }
    }

    /**
     * 所有未缴费提醒
     *
     * @param doc
     * @param hos
     */
    public void RemindAll(Doctor doc, Hospital hos) throws Exception {
            boolean flag = true;
            int page = 0;
            int start = 0;
            String sql = "select p.* " +
                    "     from " +
                    "        wlyy_sign_family f join wlyy_patient p on f.patient = p.code " +
                    "     where " +
                    "        (f.doctor = ? or f.doctor_health = ?) " +
                    "        and f.status > 0 " +
                    "        and f.type = 2 " +
                    "        and (f.expenses_status = '0' or LENGTH(trim(ifnull(f.expenses_status,''))) < 1) " +
                    "     limit ?,3000";

            while (flag) {
                List<Patient> result = jdbcTemplate.query(sql, new Object[]{doc.getCode(), doc.getCode(), start}, new BeanPropertyRowMapper(Patient.class));

                if (result != null && result.size() > 0) {
                    for (Patient p : result) {
                        if (p != null) {
                            Boolean epTime = redisTemplate.opsForSet().isMember("expenses:remind:set", p.getCode());
                            if (epTime) {
                                continue;
                            }
                            remindPatientExpenses(p, doc, hos, true);
                        }
                    }
                    page = page + 1;
                    start = page * 3000;
                } else {
                    flag = false;
                }
            }
    }

    /**
     * 提醒患者缴费
     *
     * @param patient 患者
     * @param doctor  医生
     * @return
     */
    public JSONObject remindPatientExpenses(String patient, String doctor) {
        try {
            Doctor doc = doctorDao.findByCode(doctor);
            if (doc == null) {
                throw new Exception("doctor info can not find");
            }

            Hospital hos = hospitalDao.findByCode(doc.getHospital());
            if (hos == null) {
                throw new Exception("hospital info can not find");
            }

            Patient p = patientDao.findByCode(patient);

            if (p == null) {
                throw new Exception("patient info can not find");
            }

            return remindPatientExpenses(p, doc, hos, false);
        } catch (Exception e) {
            e.printStackTrace();
            JSONObject reObj = new JSONObject();
            reObj.put("status", -1);
            reObj.put("msg", e.getMessage());
            return reObj;
        }
    }

    /**
     * 提醒患者缴费
     *
     * @param p   患者
     * @param doc 医生
     * @param hos 医院
     * @return
     */
    public JSONObject remindPatientExpenses(Patient p, Doctor doc, Hospital hos, boolean ignore) throws Exception {
        try {
            Calendar today = Calendar.getInstance();
            today.set(Calendar.HOUR,23);
            today.set(Calendar.MINUTE,59);
            today.set(Calendar.SECOND,59);
            today.set(Calendar.MILLISECOND,59);
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            JSONObject reObj = new JSONObject();
            String mDesc = "";
            boolean mFlag = false;
            boolean wFlag = false;
            boolean isMobileExist = false;
            boolean isOpenIdExist = false;

            if (StringUtils.isNotEmpty(p.getMobile())) {
                isMobileExist = true;
                JSONObject result = smsService.sendMsg(p.getMobile(), doc.getName() + "医生提醒您：为完成家庭医生签约，" +
                        "尽早为您提供家庭医生服务，请尽快到" + hos.getName() + "（地址：" + hos.getAddress() + "）缴费");
                if (result != null && result.getInt("result") == 0) {
                    mFlag = true;
                }
                if (result != null) {
                    mDesc = result.getString("description");
                }
            }
            if (StringUtils.isNotEmpty(p.getOpenid())) {
                isOpenIdExist = true;
                // 微信提醒
                JSONObject json = new JSONObject();
                json.put("first", "缴费提醒");
                json.put("toUser", p.getCode());
                json.put("name", p.getName());
                json.put("doctor", doc.getCode());
                json.put("doctorName", doc.getName());
                json.put("date", DateUtil.dateToStrShort(new Date()));
                json.put("content", p.getName() + "，您好！为完成家庭医生签约，尽早为您提供家庭医生服务，请尽快到" + hos.getName() + "（地址：" + hos.getAddress() + "）缴费");
                json.put("remark", "");
                // 添加到发送队列
                PushMsgTask.getInstance().putWxMsg(tokenUtils.getAccessToken(), 8, p.getOpenid(), p.getName(), json);
                wFlag = true;
            }
            //发送IM
            SendP2PUtil.sendP2Pmsg(doc.getCode(), p.getCode(), "1", doc.getName() + "医生提醒您：为完成家庭医生签约，" +
                    "尽早为您提供家庭医生服务，请尽快到" + hos.getName() + "（地址：" + hos.getAddress() + "）缴费");
            if (ignore) {
                redisTemplate.opsForSet().add("expenses:remind:set",p.getCode());
                redisTemplate.expireAt("expenses:remind:set", today.getTime());
            }

            if (wFlag || mFlag) {
                reObj.put("status", 200);
                redisTemplate.opsForSet().add("expenses:remind:set",p.getCode());
                redisTemplate.expireAt("expenses:remind:set", today.getTime());
                if (wFlag && mFlag) {
                    reObj.put("msg", "提醒成功");
                } else if (mFlag && !wFlag) {
                    reObj.put("msg", "已短信提醒，居民未绑定微信，无法微信提醒");
                } else {
                    if (!isMobileExist) {
                        reObj.put("msg", "已微信提醒，居民未绑定手机，无法短信提醒");
                    } else {
                        reObj.put("msg", "已微信提醒，短信提醒失败，失败原因：" + mDesc);
                    }
                }
            } else {
                reObj.put("status", -1);

                if (!isMobileExist && !isOpenIdExist) {
                    reObj.put("msg", "居民未绑定手机及微信，无法提醒");
                } else if (isMobileExist && !isOpenIdExist) {
                    reObj.put("msg", "居民未绑定微信，且短信提醒失败，无法提醒居民。短信失败原因：" + mDesc);
                } else {
                    reObj.put("msg", "提醒失败");
                }
            }

            return reObj;
        } catch (Exception e) {
            e.printStackTrace();
            JSONObject reObj = new JSONObject();
            reObj.put("status", -1);
            reObj.put("msg", e.getMessage());
            return reObj;
        }
    }


    /**
     * 提醒患者关注微信
     *
     * @param patient 患者
     * @param doctor  医生
     * @return
     */
    public JSONObject remindPatientFocusWechat(String patient, String doctor) {
        try {
            Doctor doc = doctorDao.findByCode(doctor);
            if (doc == null) {
                throw new Exception("doctor info can not find");
            }

            Patient p = patientDao.findByCode(patient);

            if (p == null) {
                throw new Exception("patient info can not find");
            }

            Map<String, Object> map = new HashMap<>();
            map.put("code", p.getCode());
            map.put("name", p.getName());
            map.put("mobile", p.getMobile());
            return remindWechatFocus(map, doc);
        } catch (Exception e) {
            e.printStackTrace();
            JSONObject reObj = new JSONObject();
            reObj.put("status", -1);
            reObj.put("msg", e.getMessage());
            return reObj;
        }
    }

    /**
     * 提醒所有患者关注微信
     *
     * @param doctor
     */
    @Async
    public void remindPatientWechatFocusAll(String doctor) throws Exception {
        try {
            int page = 0;
            int start = 0;
            boolean flag = true;
            Doctor doc = doctorDao.findByCode(doctor);
            if (doc == null) {
                throw new Exception("doctor info can not find");
            }
            String sql = "select p.code,p.name,p.mobile" +
                    "     from " +
                    "        wlyy_sign_family f join wlyy_patient p on f.patient = p.code" +
                    "     where " +
                    "        (f.doctor = ? or f.doctor_health = ?) " +
                    "        and f.status > 0 " +
                    "        and f.expenses_status = '1' " +
                    "        and LENGTH(trim(ifnull(p.openid,''))) < 1 limit ?,3000";

            while (flag) {
                List<Map<String, Object>> result = jdbcTemplate.queryForList(sql, new Object[]{doctor, doctor, start});

                if (result != null && result.size() > 0) {
                    for (Map<String, Object> map : result) {
                        boolean epTime = redisTemplate.opsForSet().isMember("wechat:focus:remind:set", map.get("code").toString());
                        if (epTime) {
                            continue;
                        }
                        remindWechatFocus(map, doc);
                    }
                    page = page + 1;
                    start = page * 3000;
                } else {
                    flag = false;
                }
            }

            redisTemplate.opsForValue().set("wechat:focus:remind:doctor:" + doctor, "0");
            redisTemplate.expire("wechat:focus:remind:doctor:" + doctor, 10, TimeUnit.MINUTES);
        } catch (Exception e) {
            redisTemplate.opsForValue().set("wechat:focus:remind:doctor:" + doctor, "0");
            redisTemplate.expire("wechat:focus:remind:doctor:" + doctor, 10, TimeUnit.MINUTES);
            e.printStackTrace();
        }
    }


    /**
     * 微信关注提醒
     *
     * @param p
     * @param doctor
     * @return
     */
    public JSONObject remindWechatFocus(Map<String, Object> p, Doctor doctor) {
        Calendar today = Calendar.getInstance();
        today.set(Calendar.HOUR,23);
        today.set(Calendar.MINUTE,59);
        today.set(Calendar.SECOND,59);
        today.set(Calendar.MILLISECOND,59);
        JSONObject result = new JSONObject();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        redisTemplate.opsForSet().add("wechat:focus:remind:set",p.get("code").toString());
        redisTemplate.expireAt("wechat:focus:remind:set", today.getTime());

        if (p.get("mobile") == null || StringUtils.isEmpty(p.get("mobile").toString())) {
            result.put("status", -1);
            result.put("msg", "对不起，居民未绑定手机号，无法短信提醒");
            return result;
        }

        String msg = "尊敬的" + p.get("name").toString() + "，" + doctor.getName() + "医生提醒您：" +
                "为更好地为您提供健康服务，请您关注并登录\"厦门i健康\"微信公众号，与医生进行互动。";

        JSONObject smsResult = smsService.sendMsg(p.get("mobile").toString(), msg);

        if (smsResult != null && smsResult.getInt("result") == 0) {
            result.put("status", 200);
            result.put("msg", "提醒成功");
        } else {
            result.put("status", -1);
            result.put("msg", "对不起，短信提醒失败，失败原因：" + smsResult.getString("description"));
        }

        return result;
    }
}
