package com.mortals.xhx.busiz.dingtalk.api;

import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.*;
import com.dingtalk.api.response.*;
import com.mortals.framework.annotation.UnAuth;
import com.mortals.framework.common.Rest;
import com.mortals.framework.exception.AppException;
import com.mortals.framework.model.Context;
import com.mortals.xhx.busiz.dingtalk.config.TalkConfiguration;
import com.mortals.xhx.busiz.dingtalk.req.*;
import com.mortals.xhx.common.pdu.ApiRespPdu;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 钉钉相关外部接口
 *
 * @Author:
 */
@RestController
@Slf4j
public class TalkApiController {

    @Autowired
    private TalkConfiguration talkConfiguration;

    private String dingToken;

    /**
     * 获取token
     *
     * @return
     */
    @PostMapping("/dingtalk/gettoken")
    @UnAuth
    public ApiRespPdu<String> getToken() {
        ApiRespPdu<String> apiRespPdu = new ApiRespPdu<>();
        try {
            DingTalkClient client = new DefaultDingTalkClient(talkConfiguration.getGetTokneUrl());
            OapiGettokenRequest req = new OapiGettokenRequest();
            req.setAppkey(talkConfiguration.getAppKey());
            req.setAppsecret(talkConfiguration.getAppSecret());
            req.setHttpMethod("GET");
            OapiGettokenResponse rsp = client.execute(req);
            log.info("gettoken rsp:" + rsp.getBody());
            if (rsp.getErrcode() == 0) {
                dingToken = rsp.getAccessToken();
                apiRespPdu.setCode(0);
                apiRespPdu.setData(rsp.getAccessToken());
                apiRespPdu.setMsg(rsp.getMsg());
            } else {
                apiRespPdu.setCode(-1);
                apiRespPdu.setData("");
                apiRespPdu.setMsg(rsp.getMsg());
            }

        } catch (Exception e) {
            log.error("异常", e);
            apiRespPdu.setCode(-1);
            apiRespPdu.setData("");
            apiRespPdu.setMsg(e.toString());
        }
        return apiRespPdu;
    }

    /**
     * 获取部门列表
     * @return
     */
    @PostMapping("/dingtalk/getSubList")
    @UnAuth
    public ApiRespPdu<List<OapiV2DepartmentListsubResponse.DeptBaseResponse>> getSubList(){
        ApiRespPdu<List<OapiV2DepartmentListsubResponse.DeptBaseResponse>> apiRespPdu = new ApiRespPdu<>();
        try {
            DingTalkClient client = new DefaultDingTalkClient(talkConfiguration.getGetSubList());
            OapiV2DepartmentListsubRequest req = new OapiV2DepartmentListsubRequest();
            if(dingToken == null){
                dingToken = getToken().getData();
            }
            OapiV2DepartmentListsubResponse rsp = client.execute(req, dingToken);
            if(rsp.getErrcode() == 0){
                apiRespPdu.setCode(0);
                apiRespPdu.setData(rsp.getResult());
                apiRespPdu.setMsg(rsp.getMsg());
            }else {
                if(getToken().getCode() == 0){
                    getSubList();
                }else {
                    apiRespPdu.setCode(-1);
                    apiRespPdu.setData(null);
                    apiRespPdu.setMsg("获取token失败");
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
            apiRespPdu.setCode(-1);
            apiRespPdu.setData(null);
            apiRespPdu.setMsg(e.toString());
        }

        return apiRespPdu;
    }


    /**
     * 根据部门id查询该部门下所有用户完整信息
     * @return
     */
    @PostMapping("/dingtalk/getUserList")
    @UnAuth
    public ApiRespPdu<OapiV2UserListResponse.PageResult> getUserList(@RequestBody UserPageReq res){
        ApiRespPdu<OapiV2UserListResponse.PageResult> apiRespPdu = new ApiRespPdu<>();
        try {
            DingTalkClient client = new DefaultDingTalkClient(talkConfiguration.getGetuserlist());
            OapiV2UserListRequest req = new OapiV2UserListRequest();
            if(dingToken == null){
                dingToken = getToken().getData();
            }
            req.setDeptId(res.getDeptid());   //部门id
            req.setCursor(res.getCursor());   //起始页游标
            req.setSize(res.getSize());    //分页条数
            OapiV2UserListResponse rsp = client.execute(req, dingToken);
            if(rsp.getErrcode() == 0){
                apiRespPdu.setCode(0);
                apiRespPdu.setData(rsp.getResult());
                apiRespPdu.setMsg(rsp.getMsg());
            }else {
                if(getToken().getCode() == 0){
                    getUserList(res);
                }else {
                    apiRespPdu.setCode(-1);
                    apiRespPdu.setData(null);
                    apiRespPdu.setMsg("获取token失败");
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
            apiRespPdu.setCode(-1);
            apiRespPdu.setData(null);
            apiRespPdu.setMsg(e.toString());
        }

        return apiRespPdu;
    }

    /**
     * 根据手机号查询用户
     * @return
     */
    @GetMapping("/dingtalk/getByMobile")
    @UnAuth
    public ApiRespPdu<OapiV2UserGetResponse.UserGetResponse> getByMobile(@RequestBody MobileReq mobile){
        ApiRespPdu<OapiV2UserGetResponse.UserGetResponse> apiRespPdu = new ApiRespPdu<>();
        try {
            DingTalkClient client = new DefaultDingTalkClient(talkConfiguration.getGetbymobile());
            OapiV2UserGetbymobileRequest req = new OapiV2UserGetbymobileRequest();
            if(dingToken == null){
                dingToken = getToken().getData();
            }
            req.setMobile(mobile.getMobile());   //用户手机号
            //先根据手机号去获取userid  再通过userid获取详情    钉钉没有直接根据电话获取用户详情的接口
            OapiV2UserGetbymobileResponse rsp = client.execute(req, dingToken);
            if(rsp.getErrcode() == 0){
                //根据获取到的userid去获取用户详情
                ApiRespPdu<OapiV2UserGetResponse.UserGetResponse> userRsp = getUserInfoByUserId(rsp.getResult().getUserid());
                if(userRsp.getCode() == 0){
                    apiRespPdu.setCode(userRsp.getCode());
                    apiRespPdu.setData(userRsp.getData());
                    apiRespPdu.setMsg(userRsp.getMsg());
                }else {
                    apiRespPdu.setCode(-1);
                    apiRespPdu.setData(null);
                    apiRespPdu.setMsg(userRsp.getMsg());
                }
            }else {
                if(getToken().getCode() == 0){
                    getByMobile(mobile);
                }else {
                    apiRespPdu.setCode(-1);
                    apiRespPdu.setData(null);
                    apiRespPdu.setMsg("获取token失败");
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
            apiRespPdu.setCode(-1);
            apiRespPdu.setData(null);
            apiRespPdu.setMsg(e.toString());
        }

        return apiRespPdu;
    }

    /**
     * 根据userid查询用户详情
     * @return
     */
    @GetMapping("/dingtalk/getUserInfoByUserId")
    @UnAuth
    public ApiRespPdu<OapiV2UserGetResponse.UserGetResponse> getUserInfoByUserId(@RequestBody String userid){
        ApiRespPdu<OapiV2UserGetResponse.UserGetResponse> apiRespPdu = new ApiRespPdu<>();
        try {
            DingTalkClient client = new DefaultDingTalkClient(talkConfiguration.getGetuserinfobyuserid());
            OapiV2UserGetRequest req = new OapiV2UserGetRequest();
            if(dingToken == null){
                dingToken = getToken().getData();
            }
            req.setUserid(userid);   //用户id
            OapiV2UserGetResponse rsp = client.execute(req, dingToken);

            apiRespPdu.setCode(0);
            apiRespPdu.setData(rsp.getResult());
            apiRespPdu.setMsg(rsp.getMsg());
        } catch (Exception e) {
            e.printStackTrace();
            apiRespPdu.setCode(-1);
            apiRespPdu.setData(null);
            apiRespPdu.setMsg(e.toString());
        }

        return apiRespPdu;
    }


    /**
     * 推送链接类钉钉工作消息
     * @return
     */
    @PostMapping("/dingtalk/sendLinkMessage")
    @UnAuth
    public ApiRespPdu<String> sendLinkMessage(@RequestBody LinkMessageReq linkMessageReq){
        ApiRespPdu<String> apiRespPdu = new ApiRespPdu<>();
        try {
            DingTalkClient client = new DefaultDingTalkClient(talkConfiguration.getSendmessage());
            if(dingToken == null){
                dingToken = getToken().getData();
            }
            OapiMessageCorpconversationAsyncsendV2Request req = new OapiMessageCorpconversationAsyncsendV2Request();
            req.setAgentId(Long.valueOf(talkConfiguration.getGetAgentId()));
            req.setUseridList(linkMessageReq.getUserIdList());

            OapiMessageCorpconversationAsyncsendV2Request.Msg obj1 = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
            obj1.setMsgtype("link");   //type为链接类消息
            OapiMessageCorpconversationAsyncsendV2Request.Link obj2 = new OapiMessageCorpconversationAsyncsendV2Request.Link();
            obj2.setPicUrl(linkMessageReq.getPicUrl());    //消息图片地址
            obj2.setMessageUrl(linkMessageReq.getMessageUrl());  //跳转链接地址
            obj2.setText(linkMessageReq.getText());    //消息描述
            obj2.setTitle(linkMessageReq.getTitle());   //消息title
            obj1.setLink(obj2);
            req.setMsg(obj1);

            OapiMessageCorpconversationAsyncsendV2Response rsp = client.execute(req, dingToken);
            if(rsp.getErrcode() == 0){
                apiRespPdu.setCode(0);
                apiRespPdu.setData(rsp.getBody());
                apiRespPdu.setMsg(rsp.getMsg());
            }else {
                apiRespPdu.setCode(-1);
                apiRespPdu.setData(rsp.getBody());
                apiRespPdu.setMsg(rsp.getMsg());

            }

        } catch (Exception e) {
            e.printStackTrace();
            apiRespPdu.setCode(-1);
            apiRespPdu.setData("");
            apiRespPdu.setMsg(e.toString());
        }

        return apiRespPdu;
    }


    /**
     * 根据免登码查询用户详情
     * @return
     */
    @GetMapping("/dingtalk/getUserInfoByCode")
    @UnAuth
    public ApiRespPdu<OapiV2UserGetuserinfoResponse.UserGetByCodeResponse> getUserInfoByCode(@RequestBody CodeReq codeReq){
        ApiRespPdu<OapiV2UserGetuserinfoResponse.UserGetByCodeResponse> apiRespPdu = new ApiRespPdu<>();
        try {
            DingTalkClient client = new DefaultDingTalkClient(talkConfiguration.getGetuserinfobycode());
            OapiV2UserGetuserinfoRequest req = new OapiV2UserGetuserinfoRequest();
            if(dingToken == null){
                dingToken = getToken().getData();
            }
            req.setCode(codeReq.getCode());    //前端js获取到的免登码  用免登码获取用户信息
            OapiV2UserGetuserinfoResponse rsp = client.execute(req, dingToken);

            apiRespPdu.setCode(0);
            apiRespPdu.setData(rsp.getResult());
            apiRespPdu.setMsg(rsp.getMsg());
        } catch (Exception e) {
            e.printStackTrace();
            apiRespPdu.setCode(-1);
            apiRespPdu.setData(null);
            apiRespPdu.setMsg(e.toString());
        }

        return apiRespPdu;
    }


    /**
     * 根据两个日期计算其中的工作时间 返回单位小时
     * @return
     */
    @PostMapping("/attendance/getTimeCount")
    @UnAuth
    public Rest<Float> getUserInfoByCode(@RequestBody TimeReq timeReq){
        Rest<Float> ret = new Rest();
        try {
            String startTime = timeReq.getStartTime();
            String endTime = timeReq.getEndTime();

            Date startMoningStart = getDate(startTime, 1);
            Date startMoningEnd = getDate(startTime,2);
            Date startAfternoonStart = getDate(startTime,3);
            Date startAfternoonEnd = getDate(startTime,4);
            Date endMoningStart = getDate(endTime,1);
            Date endMoningEnd = getDate(endTime,2);
            Date endAfternoonStart = getDate(endTime,3);
            Date endAfternoonEnd = getDate(endTime,4);
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date start = format.parse(startTime);
            Date end = format.parse(endTime);
            int hours = 1000*60*60;
            float result = 0;
            //若开始时间和结束时间是同一天
            SimpleDateFormat simple1 = new SimpleDateFormat("yyyy-MM-dd");
            simple1.format(simple1.parse(startTime)).equals(simple1.format(simple1.parse(endTime)));
            if(simple1.format(simple1.parse(startTime)).equals(simple1.format(simple1.parse(endTime)))){
                //如果结束时间比上班时间早，或者结束时间比开始时间早 或者开始时间晚于下午下班时间，则出差时长为0
                if(end.getTime() <= startMoningStart.getTime() || end.getTime()<=start.getTime() || start.getTime()>=startAfternoonEnd.getTime()
                        || isHolidays(startTime)){
                    result = 0;
                    System.out.println("出差时长为："+result);
                    ret.setCode(Rest.FAIL);
                    ret.setMsg("时间不正确");
                    return ret;
                }
                //如果结束时间在上午时间段
                if(end.getTime()<=startMoningEnd.getTime()){
                    //判断开始时间是否早与上午上班时间
                    if(start.getTime()<startMoningStart.getTime()){
                        result = (end.getTime()-startMoningStart.getTime()+0f)/hours;
                    }else{
                        result = (end.getTime()-start.getTime()+0f)/hours;
                    }
                }
                //如果结束时间在中午时间段
                if(end.getTime()>startMoningEnd.getTime() && end.getTime()<=startAfternoonStart.getTime()){
                    //如果开始时间在上午上班之前
                    if(start.getTime()<=startMoningStart.getTime()){
                        result = 4;
                    }else if(start.getTime()>startMoningStart.getTime() && start.getTime()<startMoningEnd.getTime()){
                        //开始时间在上午上班时间段
                        result = (startMoningEnd.getTime()-start.getTime()+0f)/hours;
                    } else if (start.getTime()>=startMoningStart.getTime()) {
                        //开始时间也在中午
                        result = 0;
                    }
                }
                //如果结束时间在下午上班时间段
                if(end.getTime()>startAfternoonStart.getTime() && end.getTime()<=startAfternoonEnd.getTime()){
                    if(start.getTime()<=startMoningStart.getTime()){
                        //如果开始时间在上午上班之前
                        result = 4 + (end.getTime()-startAfternoonStart.getTime()+0f)/hours;

                    } else if (start.getTime()>startMoningStart.getTime() && start.getTime()<startMoningEnd.getTime()) {
                        //如果开始时间在上午上班时间
                        result = (startMoningEnd.getTime()-start.getTime() + end.getTime()-startAfternoonStart.getTime()+0f)/hours;

                    } else if (start.getTime()>=startMoningEnd.getTime() && start.getTime()<=startAfternoonStart.getTime()) {
                        //开始时间在中午时间段
                        result = (end.getTime() - startAfternoonStart.getTime()+0f)/hours;

                    }else if(start.getTime()>startAfternoonStart.getTime()){
                        //开始时间也在下午上班时间段
                        result  = (end.getTime()-start.getTime()+0f)/hours;

                    }
                }
                //如果结束时间在下午下班之后
                if(end.getTime() > startAfternoonEnd.getTime()){
                    if(start.getTime() <= startMoningStart.getTime()){
                        //如果开始时间在上午上班之前
                        result = 8;

                    }else if(start.getTime()>startMoningStart.getTime() && start.getTime()<startMoningEnd.getTime()){
                        //开始时间在上午上班时间段
                        result = 4 + (startMoningEnd.getTime() - start.getTime()+0f)/hours;

                    } else if (start.getTime()>=startMoningEnd.getTime() && start.getTime()<=startAfternoonStart.getTime()) {
                        //如果开始时间在中午时间段
                        result = 4;

                    } else if (start.getTime()>startAfternoonStart.getTime() && start.getTime()<startAfternoonEnd.getTime()) {
                        //开始时间在下午上班时间段
                        result = (startAfternoonEnd.getTime()-start.getTime()+0f)/hours;

                    }
                }

            }else {
                if( end.getTime()<=start.getTime() ){
                    result = 0f;
                    System.out.println("出差时长为："+result);
                    ret.setCode(Rest.FAIL);
                    ret.setMsg("开始时间晚于结束时间！");
                    return ret;
                }
                //开始时间和结束时间不在同一天
                float startDayHours = getStartDayHours(start,startMoningStart,startMoningEnd,startAfternoonStart,startAfternoonEnd);
                float endDayHours = 8 - getStartDayHours(end,endMoningStart,endMoningEnd,endAfternoonStart,endAfternoonEnd);
                //计算开始时间和结束时间之间隔了几天
                int days = getDays(startTime,endTime);
                float daysHours = (days-1)*8;
                result = daysHours + startDayHours + endDayHours;
                result = deleteHolidays(startTime,endTime,startDayHours,endDayHours,result);

            }

            BigDecimal bigResult  =   new  BigDecimal(result);
            float   finalResult   =  bigResult.setScale(1,  BigDecimal.ROUND_HALF_UP).floatValue();
            System.out.println("出差时长为："+finalResult);
            ret.setCode(Rest.SUCCESS);
            ret.setData(finalResult);
            ret.setMsg("成功！");
            return ret;

        }catch (Exception e){
            ret.setCode(Rest.FAIL);
            ret.setMsg("日期格式不正确");
            return ret;
        }

    }


    //排除出差时长中的节假日时间   这里不考虑休息半天的情况
    // 开始时间startTime 结束时间endTime   开始时间当前的时长startDayHours  结束时间当天的时长endDayHours 排除节假日之前的时长
    //只有startTime 和endTime不在同一天才调用
    private static float deleteHolidays(String startTime,String endTime,float startDayHours,float endDayHours, float hours) throws ParseException {
        float result = hours+0f;
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        //1判断startTime是否是节假日，周末
        if(isHolidays(startTime)){
            result = result - startDayHours;
        }
        //轮循开始时间到结束时间   当前时间
        String nowDate = startTime;
        do{
            nowDate = format.format(DateUtils.addDays(format.parse(nowDate), 1));
            if(format.format(format.parse(nowDate)).equals(format.format(format.parse(endTime)))){
                break;
            }
            if(isHolidays(nowDate)){
                result = result - 8;
            }
        }while(true);//
        if(isHolidays(endTime)){
            result = result -endDayHours;
        }
        return result;
    }
    //判断一个日期是否是节假日 或者周末
    private static boolean isHolidays(String time) throws ParseException {
        String queryCalenderSql = "";
        //IRowSet query = DbUtil.executeQuery(ctx, queryCalenderSql);
        //    	if(query.next()){
        //    		return true;
        //    	}
        //判断是否是周末
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cal = Calendar.getInstance();
        cal.setTime(format.parse(time));
        if(cal.get(Calendar.DAY_OF_WEEK)==1 || cal.get(Calendar.DAY_OF_WEEK)==7){
            return true;
        }
        return false;
    }

    private static int getDays(String startTime,String endTime) throws ParseException {
        //计算开始和结束时间之间相差的天数
        int result = 0;
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        Date start = format.parse(startTime);
        Date end = format.parse(endTime);
        Calendar calStart = Calendar.getInstance();
        calStart.setTime(start);
        Calendar calEnd = Calendar.getInstance();
        calEnd.setTime(end);
        int startDay = calStart.get(Calendar.DAY_OF_YEAR);
        int endDay = calEnd.get(Calendar.DAY_OF_YEAR);
        int yearStart = calStart.get(Calendar.YEAR);
        int yearEnd = calEnd.get(Calendar.YEAR);
        if(yearEnd != yearStart) //不同年
        {
            int timeDistance = 0 ;
            for(int i = yearStart ; i < yearEnd ; i ++)
            {
                if(i%4==0 && i%100!=0 || i%400==0) //闰年
                {
                    timeDistance += 366;
                }
                else //不是闰年
                {
                    timeDistance += 365;
                }
            }
            System.out.println(timeDistance + (endDay-startDay));
            result = timeDistance + (endDay-startDay);

        }
        else //同一年
        {
            result = endDay-startDay;
            System.out.println("判断day2 - day1 : " + (endDay-startDay));
            //return day2-day1;
        }
        return result;
    }
    //计算开始时间那天的出差时长
    private static float getStartDayHours(Date start,Date moningStart,Date moningEnd,Date afternoonStart,Date afternoonEnd){
        float result = 0f;
        //开始时间早与上午上班时间
        if(start.getTime()<=moningStart.getTime()){
            result = 8;
        }else if(start.getTime()>moningStart.getTime() && start.getTime() <moningEnd.getTime()){
            //开始时间在上午时间段
            result = 4 + (moningEnd.getTime()-start.getTime()+0f)/(1000*60*60);
        } else if (start.getTime()>=moningEnd.getTime() && start.getTime()<=afternoonStart.getTime()) {
            //开始时间在中午时间段
            result = 4;
        }else if(start.getTime()>afternoonStart.getTime() && start.getTime()<afternoonEnd.getTime()){
            result = (afternoonEnd.getTime() - start.getTime()+0f)/(1000*60*60);
        }else if(start.getTime()>=afternoonEnd.getTime()){
            result = 0;
        }
        return result;
    }


    //获取给定日期工作时间
    private static Date getDate(String date, int type) throws ParseException {
        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        calendar.setTime(format.parse(date));
        StringBuilder result = new StringBuilder();
        if(calendar.get(Calendar.MONTH)<9){
            result.append(calendar.get(Calendar.YEAR)).append("-0");
        }else{
            result.append(calendar.get(Calendar.YEAR)).append("-");
        }
        result.append(calendar.get(Calendar.MONTH)+1).append("-");
        result.append(calendar.get(Calendar.DATE)).append(" ");
        //1上午开始时间09:00 ；2上午结束时间12:00  3下午开始时间13:00 4下午结束时间18:00
        switch (type){
            case 1:result.append("09:00");
                break;
            case 2:result.append("12:00");
                break;
            case 3:result.append("13:00");
                break;
            case 4:result.append("18:00");
                break;
        }
        return format.parse(String.valueOf(result));
    }

}
