package com.imdroid.beidou.service;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseMapper;
import com.github.yulichang.query.MPJQueryWrapper;
import com.imdroid.beidou.auth.SessionUtils;
import com.imdroid.beidou.entity.Tenant;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;

/**
 * 分页查询，excel导出通用类
 *
 * @author LiGang
 * @date 2024/1/4 22:55
 */
public interface CommonExcelService<T, R> {

    /**
     * 获取实体类的class
     *
     * @return 实体类的class
     */
    Class<R> getEntityClass();

    /**
     * 获取实体类对应的mybatis mapper
     *
     * @return 实体类对应的mybatis mapper
     */
    BaseMapper<T> getMapper();

    /**
     * 准备QueryWrapper，额外处理
     */
    default AbstractWrapper prepareQueryWrapper() {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(getOrderByColumn())) {
            if ("desc".equals(getOrder())) {
                queryWrapper.orderByDesc(getOrderByColumn());
            } else {
                queryWrapper.orderByAsc(getOrderByColumn());
            }
        }
        return queryWrapper;
    }

    /**
     * 获取排序字段，默认降序排序
     *
     * @return 排序字段
     */
    default String getOrderByColumn() {
        return "createtime";
    }

    /**
     * 获取排序方式，默认降序
     *
     * @return 排序方式
     */
    default String getOrder() {
        return "desc";
    }

    /**
     * 是否联表查询
     *
     * @return 是否联表查询
     */
    default boolean isJoinSelect() {
        return false;
    }

    default String tenantIdField() {
        return "tenantid";
    }

    /**
     * 分页查询
     *
     * @param session      HttpSession
     * @param page 页数
     * @param limit 每页条数
     * @param searchParams json格式的搜索字段
     * @return page list record
     */
    default JSONObject pageList(HttpSession session, Integer page, Integer limit, String searchParams) {
        Page pageable = new Page<>(page == null ? 1 : page, limit == null ? 10 : limit);

        // 检查查询条件
        JSONObject search = null;
        if (searchParams != null) {
            search = (JSONObject) JSONObject.parse(searchParams);
        }
        checkSearchParams(search);

        // 构造wrapper
        AbstractWrapper queryWrapper = prepareQueryWrapper();
        Integer tenantId = (Integer) session.getAttribute(SessionUtils.SESSION_TENANT_ID);
        if (tenantId != null && tenantId != Tenant.SAAS_PROVIDER_ID) {
            queryWrapper.eq(tenantIdField(), tenantId);
        }
        if (search != null) {
            for (Map.Entry<String, Object> entry : search.entrySet()) {
                setQueryWrapper(queryWrapper, entry.getKey(), entry.getValue());
            }
        }

        // 查询
        IPage<R> cs = null;
        if (isJoinSelect()) {
            MPJBaseMapper baseMapper = (MPJBaseMapper) getMapper();
            MPJQueryWrapper<T> mpjQueryWrapper = (MPJQueryWrapper<T>) queryWrapper;
            cs = baseMapper.selectJoinPage(pageable, getEntityClass(), mpjQueryWrapper);
        } else {
            cs = getMapper().selectPage(pageable, queryWrapper);
        }

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", 0);
        jsonObject.put("msg", "");
        jsonObject.put("count", cs.getTotal());
        jsonObject.put("data", cs.getRecords());
        return jsonObject;
    }

    /**
     * 导出excel
     *
     * @param session      HttpSession
     * @param request HttpServletRequest
     * @param response     HttpServletResponse
     * @throws Exception
     */
    default void export(HttpSession session, HttpServletRequest request, HttpServletResponse response) throws Exception {
        AbstractWrapper queryWrapper = prepareQueryWrapper();

        Integer tenantId = (Integer) session.getAttribute(SessionUtils.SESSION_TENANT_ID);
        if (tenantId != null && tenantId != Tenant.SAAS_PROVIDER_ID) {
            queryWrapper.eq(tenantIdField(), tenantId);
        }

        // 条件查询
        Enumeration<String> enu = request.getParameterNames();
        while (enu.hasMoreElements()) {
            String paraName = (String) enu.nextElement();
            String paraValue = request.getParameter(paraName);
            setQueryWrapper(queryWrapper, paraName, paraValue);
        }
        List cs = null;
        if (isJoinSelect()) {
            MPJBaseMapper baseMapper = (MPJBaseMapper) getMapper();
            MPJQueryWrapper<T> mpjQueryWrapper = (MPJQueryWrapper<T>) queryWrapper;
            cs = baseMapper.selectJoinList(getEntityClass(), mpjQueryWrapper);
        } else {
            cs = getMapper().selectList(queryWrapper);
        }
        // 设置文本内省
        response.setContentType("application/vnd.ms-excel");
        // 设置字符编码
        response.setCharacterEncoding("utf-8");
        // 设置响应头
        String filename = System.currentTimeMillis() + "_" + getEntityClass().getSimpleName() + ".xlsx";
        response.setHeader("Content-disposition", "attachment;filename=" + filename);
        EasyExcel.write(response.getOutputStream(), getEntityClass()).sheet("sheet").doWrite(cs);
    }

    default void checkSearchParams(JSONObject search){}

    /**
     * 设置查询条件
     *
     * @param queryWrapper QueryWrapper
     * @param paraName 查询参数名称
     * @param paraValue 查询参数值
     */
    default void setQueryWrapper(AbstractWrapper queryWrapper, String paraName, Object paraValue) {
        // String
        if (paraName.startsWith("s") && !StringUtils.isEmpty(paraValue)) {
            addStringQueryWrapper(queryWrapper, paraName, paraValue);
        }
        // Number
        else if (paraName.startsWith("n") && !StringUtils.isEmpty(paraValue)) {
            addNumberQueryWrapper(queryWrapper, paraName, paraValue);
        }
        // Date & Time
        else if (paraName.startsWith("d") && !StringUtils.isEmpty(paraValue)) {
            addDateQueryWrapper(queryWrapper, paraName, paraValue);
        }
        // Boolean
        else if (paraName.startsWith("b") && !StringUtils.isEmpty(paraValue)) {
            addBooleanQueryWrapper(queryWrapper, paraName, paraValue);
        }
    }

    default String getColumn(String paraName) {
        return paraName.substring(paraName.indexOf("_") + 1);
    }

    default void addStringQueryWrapper(AbstractWrapper queryWrapper, String paraName, Object paraValue) {
        String column = getColumn(paraName);
        String value = paraValue.toString();
        if (StringUtils.isEmpty(value)) {
            return;
        }
        if (paraName.startsWith("s_")) {
            queryWrapper.eq(column, value);
        }
        if (paraName.startsWith("sn_")) {
            queryWrapper.ne(column, value);
        }
        if (paraName.startsWith("sl_")) {
            queryWrapper.like(column, value);
        }
        if (paraName.startsWith("slr_")) {
            queryWrapper.likeRight(column, value);
        }
        if (paraName.startsWith("sll_")) {
            queryWrapper.likeLeft(column, value);
        }

    }

    default void addNumberQueryWrapper(AbstractWrapper queryWrapper, String paraName, Object paraValue) {
        String column = getColumn(paraName);
        if (paraName.startsWith("n_")) {
            queryWrapper.eq(column, paraValue);
        }
        if (paraName.startsWith("nn_")) {
            queryWrapper.ne(column, paraValue);
        }
        if (paraName.startsWith("ngt_")) {
            queryWrapper.gt(column, paraValue);
        }
        if (paraName.startsWith("ngte_")) {
            queryWrapper.ge(column, paraValue);
        }
        if (paraName.startsWith("nlt_")) {
            queryWrapper.lt(column, paraValue);
        }
        if (paraName.startsWith("nlte_")) {
            queryWrapper.le(column, paraValue);
        }
    }

    default void addDateQueryWrapper(AbstractWrapper queryWrapper, String paraName, Object paraValue) {
        String column = getColumn(paraName);
        if (paraName.startsWith("d_")) {
            queryWrapper.eq(column, paraValue);
        }
        if (paraName.startsWith("dn_")) {
            queryWrapper.ne(column, paraValue);
        }
        if (paraName.startsWith("dgt_")) {
            queryWrapper.gt(column, paraValue);
        }
        if (paraName.startsWith("dgte_")) {
            queryWrapper.ge(column, paraValue);
        }
        if (paraName.startsWith("dlt_")) {
            queryWrapper.lt(column, paraValue);
        }
        if (paraName.startsWith("dlte_")) {
            queryWrapper.le(column, paraValue);
        }
    }

    default void addBooleanQueryWrapper(AbstractWrapper queryWrapper, String paraName, Object paraValue) {
        String column = getColumn(paraName);
        if (paraName.startsWith("b_")) {
            queryWrapper.eq(column, paraValue);
        }
    }

}
