package com.usoftchina.dingtalk.sdk;

import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiAttendanceListRecordRequest;
import com.dingtalk.api.request.OapiAttendanceListRequest;
import com.dingtalk.api.request.OapiCheckinRecordGetRequest;
import com.dingtalk.api.request.OapiCheckinRecordRequest;
import com.dingtalk.api.response.OapiAttendanceListRecordResponse;
import com.dingtalk.api.response.OapiAttendanceListResponse;
import com.dingtalk.api.response.OapiCheckinRecordGetResponse;
import com.dingtalk.api.response.OapiCheckinRecordResponse;
import com.usoftchina.dingtalk.sdk.config.DingTalkProperties;
import com.usoftchina.dingtalk.sdk.util.DateUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * oa
 * 签到、考勤
 *
 * @author yingp
 * @date 2020/2/19
 */
public class OaSdk extends BaseSdk {
    public OaSdk(DingTalkProperties properties) {
        super(properties);
    }

    /**
     * 获取部门用户签到记录
     * 企业使用此接口可获取部门人员的签到记录，进行统计分析，也可以基于高德地图（http://lbs.amap.com/）API接口开发人员分布图和热力图。
     * <p>
     * 注意：目前最多获取1000人以内的签到数据，如果所传部门ID及其子部门下的user超过1000，会报错。
     * </p>
     *
     * @param agentCode
     * @param departmentId
     * @param startTime    起始时间。Unix时间戳，如：1520956800000
     * @param endTime      结束时间。Unix时间戳，如：1520956800000。开始时间和结束时间的间隔不能大于45天
     * @return
     */
    public List<OapiCheckinRecordResponse.Data> getCheckinData(String agentCode, long departmentId, long startTime, long endTime) {
        List<OapiCheckinRecordResponse.Data> dataList = new ArrayList<>();
        long size = 100;
        int i = 0;
        while (true) {
            List<OapiCheckinRecordResponse.Data> tempList = getCheckinData(agentCode, departmentId, startTime, endTime, i++, size);
            if (null != tempList) {
                dataList.addAll(tempList);
                if (tempList.size() < size) {
                    break;
                }
            } else {
                break;
            }
        }
        return dataList;
    }

    /**
     * 分页获取部门用户签到记录
     * 企业使用此接口可获取部门人员的签到记录，进行统计分析，也可以基于高德地图（http://lbs.amap.com/）API接口开发人员分布图和热力图。
     * <p>
     * 注意：目前最多获取1000人以内的签到数据，如果所传部门ID及其子部门下的user超过1000，会报错。
     * </p>
     *
     * @param agentCode
     * @param departmentId
     * @param startTime
     * @param endTime
     * @param offset       支持分页查询，与size 参数同时设置时才生效，此参数代表偏移量，从0、1、2...依次递增
     * @param size         支持分页查询，与offset 参数同时设置时才生效，此参数代表分页大小，最大100
     * @return
     */
    public List<OapiCheckinRecordResponse.Data> getCheckinData(String agentCode, long departmentId, long startTime, long endTime, long offset, long size) {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/checkin/record");
        OapiCheckinRecordRequest req = new OapiCheckinRecordRequest();
        req.setDepartmentId(String.valueOf(departmentId));
        req.setStartTime(startTime);
        req.setEndTime(endTime);
        req.setOffset(offset);
        req.setOrder("asc");
        req.setSize(size);
        req.setHttpMethod("GET");
        OapiCheckinRecordResponse resp = cached(() -> client.execute(req, getAccessToken(agentCode)));
        assertOK(resp);
        return resp.getData();
    }

    /**
     * 获取用户签到记录
     * 企业使用此接口可获取指定人员的签到记录，进行统计分析，也可以基于高德地图（http://lbs.amap.com）API接口开发人员分布图和热力图。
     *
     * @param agentCode
     * @param userIdList
     * @param startTime  起始时间。Unix时间戳，如：1520956800000
     * @param endTime    结束时间。Unix时间戳，如：1520956800000。如果是取1个人的数据，时间范围最大到10天，如果是取多个人的数据，时间范围最大1天。
     * @return
     */
    public List<OapiCheckinRecordGetResponse.CheckinRecordVo> getCheckinData(String agentCode, List<String> userIdList, long startTime, long endTime) {
        List<OapiCheckinRecordGetResponse.CheckinRecordVo> dataList = new ArrayList<>();
        long size = 100;
        int i = 0;
        while (true) {
            List<OapiCheckinRecordGetResponse.CheckinRecordVo> tempList = getCheckinData(agentCode, userIdList, startTime, endTime, i++, size);
            if (null != tempList) {
                dataList.addAll(tempList);
                if (tempList.size() < size) {
                    break;
                }
            } else {
                break;
            }
        }
        return dataList;
    }

    /**
     * 分页获取用户签到记录
     * 企业使用此接口可获取指定人员的签到记录，进行统计分析，也可以基于高德地图（http://lbs.amap.com）API接口开发人员分布图和热力图。
     *
     * @param agentCode
     * @param userIdList
     * @param startTime
     * @param endTime
     * @param cursor     分页查询的游标，最开始可以传0，然后以1、2依次递增
     * @param size       分页查询的每页大小，最大100
     * @return
     */
    public List<OapiCheckinRecordGetResponse.CheckinRecordVo> getCheckinData(String agentCode, List<String> userIdList, long startTime, long endTime, long cursor, long size) {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/checkin/record/get");
        OapiCheckinRecordGetRequest req = new OapiCheckinRecordGetRequest();
        req.setStartTime(startTime);
        req.setEndTime(endTime);
        req.setSize(size);
        req.setCursor(cursor);
        req.setUseridList(String.join(",", userIdList));
        OapiCheckinRecordGetResponse resp = cached(() -> client.execute(req, getAccessToken(agentCode)));
        assertOK(resp);
        return resp.getResult().getPageList();
    }


    /**
     * 获取打卡详情
     * 该接口用于返回企业内员工的实际打卡记录。比如，企业给一个员工设定的排班是上午9点和下午6点各打一次卡，但是员工在这期间打了多次，该接口会把所有的打卡记录都返回。
     * <p>
     * 如果只要获取打卡结果数据，不需要详情数据，可使用获取打卡结果接口。
     * </p>
     *
     * @param agentCode
     * @param userIdList 企业内的员工id列表，最多不能超过50个
     * @param startTime  查询考勤打卡记录的起始工作日。格式为“yyyy-MM-dd hh:mm:ss”。
     * @param endTime    查询考勤打卡记录的结束工作日。格式为“yyyy-MM-dd hh:mm:ss”。注意，起始与结束工作日最多相隔7天
     */
    public List<OapiAttendanceListRecordResponse.Recordresult> getAttendanceRecordList(String agentCode, List<String> userIdList, long startTime, long endTime) {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/attendance/listRecord");
        OapiAttendanceListRecordRequest req = new OapiAttendanceListRecordRequest();
        req.setCheckDateFrom(DateUtils.formatDateTime(startTime));
        req.setCheckDateTo(DateUtils.formatDateTime(endTime));
        req.setUserIds(userIdList);
        OapiAttendanceListRecordResponse resp = cached(() -> client.execute(req, getAccessToken(agentCode)));
        assertOK(resp);
        return resp.getRecordresult();
    }

    /**
     * 获取打卡结果
     * 该接口用于返回企业内员工的实际打卡结果。比如，企业给一个员工设定的排班是上午9点和下午6点各打一次卡，即使员工在这期间打了多次，该接口也只会返回两条记录，包括上午的打卡结果和下午的打卡结果。
     * <p>
     * 如果要获取打卡详细数据，比如打卡位置，可使用获取打卡详情接口。
     * </p>
     *
     * @param agentCode
     * @param userIdList
     * @param startTime  查询考勤打卡记录的起始工作日。格式为“yyyy-MM-dd HH:mm:ss”，HH:mm:ss可以使用00:00:00，将返回此日期从0点到24点的结果
     * @param endTime    查询考勤打卡记录的结束工作日。格式为“yyyy-MM-dd HH:mm:ss”，HH:mm:ss可以使用00:00:00，将返回此日期从0点到24点的结果。注意，起始与结束工作日最多相隔7天
     * @param offset     表示获取考勤数据的起始点，第一次传0，如果还有多余数据，下次获取传的offset值为之前的offset+limit，0、1、2...依次递增
     * @param limit      表示获取考勤数据的条数，最大不能超过50条
     * @return
     */
    public List<OapiAttendanceListResponse.Recordresult> getAttendanceList(String agentCode, List<String> userIdList, long startTime, long endTime, long offset, long limit) {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/attendance/list");
        OapiAttendanceListRequest req = new OapiAttendanceListRequest();
        req.setWorkDateFrom(DateUtils.formatDateTime(startTime));
        req.setWorkDateTo(DateUtils.formatDateTime(endTime));
        req.setUserIdList(userIdList);
        req.setOffset(offset);
        req.setLimit(limit);
        OapiAttendanceListResponse resp = cached(() -> client.execute(req, getAccessToken(agentCode)));
        assertOK(resp);
        return resp.getRecordresult();
    }

    /**
     * 获取打卡结果
     * 该接口用于返回企业内员工的实际打卡结果。比如，企业给一个员工设定的排班是上午9点和下午6点各打一次卡，即使员工在这期间打了多次，该接口也只会返回两条记录，包括上午的打卡结果和下午的打卡结果。
     * <p>
     * 如果要获取打卡详细数据，比如打卡位置，可使用获取打卡详情接口。
     * </p>
     *
     * @param agentCode
     * @param userIdList
     * @param startTime  查询考勤打卡记录的起始工作日。格式为“yyyy-MM-dd HH:mm:ss”，HH:mm:ss可以使用00:00:00，将返回此日期从0点到24点的结果
     * @param endTime    查询考勤打卡记录的结束工作日。格式为“yyyy-MM-dd HH:mm:ss”，HH:mm:ss可以使用00:00:00，将返回此日期从0点到24点的结果。注意，起始与结束工作日最多相隔7天
     * @return
     */
    public List<OapiAttendanceListResponse.Recordresult> getAttendanceList(String agentCode, List<String> userIdList, long startTime, long endTime) {
        List<OapiAttendanceListResponse.Recordresult> dataList = new ArrayList<>();
        long size = 100;
        int i = 0;
        while (true) {
            List<OapiAttendanceListResponse.Recordresult> tempList = getAttendanceList(agentCode, userIdList, startTime, endTime, i++ * size, size);
            if (null != tempList) {
                dataList.addAll(tempList);
                if (tempList.size() < size) {
                    break;
                }
            } else {
                break;
            }
        }
        return dataList;
    }
}
