package com.boman.web.core.service.attendance;

import com.alibaba.fastjson.JSONObject;
import com.boman.common.core.utils.DateUtils;
import com.boman.common.core.utils.SecurityUtils;
import com.boman.common.core.utils.obj.ObjectUtils;
import com.boman.common.redis.RedisKey;
import com.boman.domain.GenTable;
import com.boman.domain.GenTableColumn;
import com.boman.domain.constant.FormDataConstant;
import com.boman.domain.dto.AjaxResult;
import com.boman.domain.dto.ClockOnDto;
import com.boman.domain.dto.FormDataDto;
import com.boman.web.core.service.TableServiceCmdService;
import com.boman.web.core.service.attendance.rules.AttendanceRulesService;
import com.boman.web.core.service.common.ICommonService;
import com.boman.web.core.service.select.IBaseSelectService;
import com.boman.web.core.utils.AuthUtils;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

import static com.boman.common.core.utils.DateUtils.YYYY_MM_DD_HH_MM;
import static com.boman.common.core.utils.number.NumberUtils.gtZero;
import static com.boman.common.core.utils.obj.ObjectUtils.*;
import static com.boman.domain.constant.AttendanceConst.*;
import static com.boman.domain.constant.AttendanceRulesConst.ATTENDANCE_RULES_END_TIME;
import static com.boman.domain.constant.AttendanceRulesConst.ATTENDANCE_RULES_START_TIME;
import static com.boman.domain.constant.FormDataConstant.CONDITION;
import static com.boman.domain.constant.FormDataConstant.PAGE_ROWS;
import static com.boman.web.core.utils.ColumnUtils.withoutHrReturnColumnNames;
import static com.boman.web.core.utils.HandlerFormDataUtils.handleNullColumnValue;

/**
 * @author shiqian
 * @date 2021年06月03日 15:45
 **/
@Service
public class AttendanceServiceImpl implements AttendanceService {

    private static final Logger LOGGER = LoggerFactory.getLogger(AttendanceServiceImpl.class);

    @Resource
    private ICommonService commonService;
    @Resource
    private AttendanceRulesService rulesService;
    @Resource
    private TableServiceCmdService cmdService;
    @Resource
    private IBaseSelectService selectService;

    /**
     * 功能描述: 根据tableName和userId查找当月考勤
     *
     * @param tableName tableName
     * @param userName  userName
     * @return java.util.List<com.alibaba.fastjson.JSONObject>
     */
    private List<JSONObject> listByUserName(String tableName, String userName) {
        requireNonNull(tableName, "tableName is empty");
        requireNonNull(userName, "userName is empty");

        List<String> days = DateUtils.getMonthDays();
        JSONObject map = new JSONObject(2);
        map.put(ATTENDANCE_USER_NAME, userName);
        map.put(ATTENDANCE_TABLE_TODAYTIME, days);
        return commonService.getByMap(tableName, map);
    }

    /**
     * 手机端考勤记录页面
     * 功能描述: 根据tableName和userId查找当月考勤
     *
     * @param tableName tableName
     * @param userName  userName
     * @return java.util.List<com.alibaba.fastjson.JSONObject>
     */
    @Override
    public AjaxResult attendanceRecord(String tableName, String userName) {
        Map<String, Object> mapObj = new HashMap<>(4);
        List<JSONObject> byMap = listByUserName(tableName, userName);
        if (isEmpty(byMap)) {
            mapObj.put("leave", 0);
            mapObj.put("late", 0);
            mapObj.put("leaveOr", 0);
            mapObj.put("dateList", new ArrayList<>(0));
            return AjaxResult.success(mapObj);
        }

        List<String> dateList = new ArrayList<>(byMap.size());
        //  早退        迟到      请假
        int leave = 0, late = 0, leaveOr = 0;
        for (JSONObject jsonObject : byMap) {
            if (ObjectUtils.isNotEmpty(jsonObject.get("attendance_table_leave")) && "Y".equals(String.valueOf(jsonObject.get("attendance_table_leave")))) {
                leave++;
            }

            if (ObjectUtils.isNotEmpty(jsonObject.get("attendance_table_late")) && "Y".equals(String.valueOf(jsonObject.get("attendance_table_late")))) {
                late++;
            }

            if (ObjectUtils.isNotEmpty(jsonObject.get("attendance_table_leave_or")) && "Y".equals(String.valueOf(jsonObject.get("attendance_table_leave_or")))) {
                leaveOr++;
            }

            if (ObjectUtils.isNotEmpty(jsonObject.get("attendance_table_todaytime"))) {
                // 只需要异常的
                if (gtZero(leave) || gtZero(late) || gtZero(leaveOr)) {
                    dateList.add(jsonObject.getString("attendance_table_todaytime"));
                }
            }
        }

        mapObj.put("leave", leave);
        mapObj.put("late", late);
        mapObj.put("leaveOr", leaveOr);
        mapObj.put("dateList", dateList);
        return AjaxResult.success(mapObj);
    }


    /**
     * 根据tableName和userId查找当月考勤详细记录
     *
     * @param dto
     * @return
     */
    @Override
    public AjaxResult detailedRecord(FormDataDto dto) {
        // 查询条件
        JSONObject condition = ifNullSetEmpty(dto.getFixedData().getJSONObject(CONDITION));
        String tableName = dto.getTable();
        GenTable genTable = cmdService.getTableFromRedisByTableName(RedisKey.TABLE_INFO, dto.getTable());
        List<GenTableColumn> columns = genTable.getColumns();
        JSONObject packCondition = ifNullSetEmpty(selectService.packColCondition(columns, condition));
        int total = selectService.countByCondition(tableName, condition, packCondition);
        JSONObject result = new JSONObject();
        result.put(FormDataConstant.PAGE_TOTAL, total);
        if (total <= 0) {
            result.put(FormDataConstant.PAGE_ROWS, null);
            return AjaxResult.success(result);
        }
        List<String> showData = withoutHrReturnColumnNames(columns);
        List<JSONObject> rows = selectService.selectByCondition(tableName, condition, packCondition, showData, dto);
        // 查询时为null的列不显示的处理
        handleNullColumnValue(rows, showData);

        List<Map<String, Object>> detailedRecordList = new ArrayList<>();
        if (isEmpty(rows)) {
            result.put(FormDataConstant.PAGE_ROWS, rows);
            return AjaxResult.success(result);
        }

        for (JSONObject jsonObject : rows) {
            Map<String, Object> map = new HashMap<>(5);
            Object attendanceTableWork = jsonObject.get("attendance_table_work");
            Object attendanceTableOffWork = jsonObject.get("attendance_table_offwork");
            map.put("attendanceTableWork", "未打卡");
            map.put("attendanceTableOffWork", "未打卡");
            if (isNotEmpty(attendanceTableWork)) {
                map.put("attendanceTableWork", attendanceTableWork + "已打卡");
            }
            if (isNotEmpty(attendanceTableOffWork)) {
                map.put("attendanceTableWork", attendanceTableOffWork + "已打卡");
            }

            map.put("dateTime", jsonObject.get("attendance_table_week") + " " + jsonObject.get("attendance_table_todaytime"));
            detailedRecordList.add(map);
        }

        result.put(PAGE_ROWS, detailedRecordList);
        return AjaxResult.success(result);
    }

    /**
     * 功能描述: 显示是上班打卡还是下班打卡
     *
     * @param tableName tableName
     * @param userName  userName
     * @return java.lang.String
     */
    @Override
    public String showAttendanceType(String tableName, String userName) {
        requireNonNull(tableName, "tableName is empty");
        requireNonNull(userName, "userName is empty");

        FormDataDto dto = new FormDataDto();
        dto.setTable(tableName);
        JSONObject condition = new JSONObject();
        condition.put("attendance_table_username", userName);
        // in
        condition.put(ATTENDANCE_TABLE_TODAYTIME, Lists.newArrayList(DateUtils.getDate()));
        dto.setFixedData(condition);
        int count = commonService.count(dto);
        return count > 0 ? GO_OFF_WORK : GO_TO_WORK;
    }

    @Override
    public List<JSONObject> checkAttendanceType(String tableName, String userName) {
        requireNonNull(tableName, "tableName is empty");
        requireNonNull(userName, "userName is empty");

        String yyyyMmDd = DateUtils.getYyyyMmDd();
        JSONObject map = new JSONObject(2);
        map.put(ATTENDANCE_USER_NAME, userName);
        map.put(ATTENDANCE_TABLE_WORK, yyyyMmDd);
        return commonService.getByMap(tableName, map);
    }

    /**
     * 功能描述: 查询该人的一天打卡时间
     *
     * @param tableName tableName
     * @param userName  userName
     * @return com.boman.domain.dto.AjaxResult
     */
    @Override
    public JSONObject attendanceTime(String tableName, String userName) {
        requireNonNull(tableName, "tableName is empty");
        requireNonNull(userName, "userName is empty");

        JSONObject result = new JSONObject();
        List<JSONObject> attendanceList = listByUserNameAndTime(tableName, userName, DateUtils.getDate());
        // 今天 还未打卡
        if (isEmpty(attendanceList)) {
            result.put(GO_TO_WORK, null);
            result.put(GO_OFF_WORK, null);
            return result;
        }

        attendanceList = attendanceList.stream()
                .sorted(Comparator.comparing(json -> json.getTimestamp(ATTENDANCE_TABLE_CREATE_TIME)))
                .collect(Collectors.toList());

        Timestamp goToWorkTime = null;
        Timestamp goOffWorkTime = null;
        for (JSONObject attendance : attendanceList) {
            if (isNotEmpty(attendance.get(ATTENDANCE_TABLE_WORK)) && isEmpty(attendance.get(ATTENDANCE_TABLE_OFFWORK))) {
                goToWorkTime = attendance.getTimestamp(ATTENDANCE_TABLE_WORK);
                break;
            }
        }

         for (JSONObject attendance : attendanceList) {
            if (isNotEmpty(attendance.get(ATTENDANCE_TABLE_OFFWORK)) && isEmpty(attendance.get(ATTENDANCE_TABLE_WORK))) {
                goOffWorkTime = attendance.getTimestamp(ATTENDANCE_TABLE_OFFWORK);
            }
        }

        result.put(GO_TO_WORK, goToWorkTime == null ? null : goToWorkTime.toString());
        result.put(GO_OFF_WORK, goOffWorkTime == null ? null : goOffWorkTime.toString());
        return result;
    }

    /**
     * 功能描述: 打卡
     *
     * @param dto     dto
     * @return com.alibaba.fastjson.JSONObject
     */
    @Override
    public JSONObject clockOn(ClockOnDto dto) {
        int type = requireNonNull(dto.getType(), "clockOn type is empty");
        String tableName = requireNonNull(dto.getTableName(), "clockOn tableName is empty");

        JSONObject commitData = new JSONObject();
        commitData.put(ATTENDANCE_USER_NAME, SecurityUtils.getUsername());
        commitData.put(ATTENDANCE_TABLE_TODAYTIME, Lists.newArrayList(DateUtils.getDate()));
        commitData.put(ATTENDANCE_TABLE_LONGITUDE, dto.getLongitude());
        commitData.put(ATTENDANCE_TABLE_LATITUDE, dto.getLatitude());
        Timestamp currentTime = new Timestamp(System.currentTimeMillis());
        // 是否请假
        if (checkIsLeave()) {
            //
        }

        if (GO_TO_WORK_TYPE == type) {
            commitData.put(ATTENDANCE_TABLE_WORK, currentTime);
            if (checkIsLate(currentTime)) {
                commitData.put(ATTENDANCE_ABNORMAL, Y);
                commitData.put(ATTENDANCE_TABLE_LATE, Y);
            }

        } else if (GO_OFF_WORK_TYPE == type) {
            commitData.put(ATTENDANCE_TABLE_OFFWORK, currentTime);
        }

        saveClockOn(tableName, commitData);
        return commitData;
    }

    /**
     * 功能描述: 保存打卡信息
     *
     * @param tableName  tableName
     * @param commitData commitData
     * @return boolean
     */
    private boolean saveClockOn(String tableName, JSONObject commitData) {
        FormDataDto dto = new FormDataDto();
        dto.setObjId(-1L);
        dto.setTable(tableName);
        dto.setFixedData(commitData);
        AjaxResult ajaxResult = cmdService.objectSave(dto);
        return AjaxResult.checkSuccess(ajaxResult);
    }

    /**
     * 功能描述: 是否迟到
     *
     * @param arrivalTime 上班打卡时间
     * @return boolean
     */
    private boolean checkIsLate(Timestamp arrivalTime) {
        JSONObject rule = rulesService.listByDeptId(AuthUtils.getLoginUser().getSysUser().getDeptId());
        String hourMi = rule.getString(ATTENDANCE_RULES_START_TIME);
        String year_month = DateUtils.getDate();
        String ruleStartTime = year_month + " " + hourMi;
        Date date = DateUtils.strToDate(ruleStartTime, YYYY_MM_DD_HH_MM);
        return arrivalTime.after(date);
    }

    /**
     * 功能描述: 是否早退
     *
     * @param leaveTime 下班打卡时间
     * @return boolean
     */
    private boolean checkIsLeaveEarly(Timestamp leaveTime) {
        JSONObject rule = rulesService.listByDeptId(AuthUtils.getLoginUser().getSysUser().getDeptId());
        Timestamp ruleEndTime = rule.getTimestamp(ATTENDANCE_RULES_END_TIME);
        return leaveTime.before(ruleEndTime);
    }


    private boolean checkIsLeave() {


        return true;
    }

    /**
     * 功能描述: 根据username和time查找
     *
     * @param tableName tableName
     * @param userName  userName
     * @param time      time
     * @return java.util.List<com.alibaba.fastjson.JSONObject>
     */
    private List<JSONObject> listByUserNameAndTime(String tableName, String userName, String time) {
        JSONObject condition = new JSONObject(2);
        condition.put(ATTENDANCE_USER_NAME, userName);
        condition.put(ATTENDANCE_TABLE_TODAYTIME, Lists.newArrayList(time));
        return commonService.getByMap(tableName, condition);
    }

}
