package com.github.wxiaoqi.security.common.rest;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.github.wxiaoqi.security.common.annotation.HeadName;
import com.github.wxiaoqi.security.common.biz.BaseBiz;
import com.github.wxiaoqi.security.common.context.BaseContextHandler;
import com.github.wxiaoqi.security.common.msg.ObjectRestResponse;
import com.github.wxiaoqi.security.common.msg.TableResultResponse;
import com.github.wxiaoqi.security.common.util.Query;
import com.github.wxiaoqi.security.common.util.ReflectionUtils;
import com.github.wxiaoqi.security.common.util.excel.ExcelImport;
import com.github.wxiaoqi.security.common.vo.PageDataVO;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;

/**
 * ${DESCRIPTION}
 *
 * @author wanghaobin
 * @create 2017-06-15 8:48
 */
@Slf4j
public class BaseController<Biz extends BaseBiz,Entity> extends CommonBaseController{
    @Autowired
    protected Biz baseBiz;

    public Biz getBaseBiz() {
        return baseBiz;
    }

    @ApiOperation("添加")
    @RequestMapping(value = "",method = RequestMethod.POST)
    @ResponseBody
    public ObjectRestResponse<Entity> add(@RequestBody Entity entity) throws Exception {
        baseBiz.insertSelective(entity);
        return new ObjectRestResponse<Entity>();
    }

    @ApiOperation("查询")
    @RequestMapping(value = "/{id}",method = RequestMethod.GET)
    @ResponseBody
    public ObjectRestResponse<Entity> get(@PathVariable int id){
        ObjectRestResponse<Entity> entityObjectRestResponse = new ObjectRestResponse<>();
        Object o = baseBiz.selectById(id);
        entityObjectRestResponse.data((Entity)o);
        return entityObjectRestResponse;
    }

    @ApiOperation("修改")
    @RequestMapping(value = "/{id}",method = RequestMethod.PUT)
    @ResponseBody
    public ObjectRestResponse<Entity> update(@RequestBody Entity entity) throws Exception {
        baseBiz.updateSelectiveById(entity);
        return new ObjectRestResponse<Entity>();
    }

    @ApiOperation("删除")
    @RequestMapping(value = "/{id}",method = RequestMethod.DELETE)
    @ResponseBody
    public ObjectRestResponse<Entity> remove(@PathVariable int id){
        baseBiz.deleteById(id);
        return new ObjectRestResponse<Entity>();
    }

    @ApiOperation("查询所有")
    @RequestMapping(value = "/all",method = RequestMethod.GET)
    @ResponseBody
    public List<Entity> all() throws Exception {
        return baseBiz.selectListAll();
    }

    @ApiOperation("查询分页")
    @RequestMapping(value = "/page",method = RequestMethod.GET)
    @ResponseBody
    public TableResultResponse<Entity> list(@RequestParam Map<String, Object> params){
        //查询列表数据
        Query query = new Query(params);
        return baseBiz.selectByQuery(query);
    }

    @ApiOperation("查询分页-ObjectRestResponse")
    @RequestMapping(value = "/pages",method = RequestMethod.GET)
    @ResponseBody
    public ObjectRestResponse<PageDataVO<Entity>> pages(@RequestParam Map<String, Object> params){
        //查询列表数据
        Query query = new Query(params);
        return ObjectRestResponse.succ(baseBiz.selectByQueryPage(query));
    }

    @ApiOperation("查询分页-ObjectRestResponse")
    @RequestMapping(value = "/baseLogicPages",method = RequestMethod.GET)
    @ResponseBody
    public ObjectRestResponse<PageDataVO<Entity>> baseLogicPages(@RequestParam Map<String, Object> params){
        //查询列表数据
        Query query = new Query(params);
        return ObjectRestResponse.succ(baseBiz.selectByQueryLogicPage(query));
    }

    @ApiOperation("根据参数查询，等于")
    @RequestMapping(value = "/entityList",method = RequestMethod.GET)
    @ResponseBody
    public ObjectRestResponse<List<Entity>> entityList(Entity entity){
        //查询列表数据
        return ObjectRestResponse.succ(baseBiz.selectList(entity));
    }

    @ApiOperation("删除")
    @RequestMapping(value = "/del",method = RequestMethod.DELETE)
    @ResponseBody
    public ObjectRestResponse del( Entity entity){
        Field field = ReflectionUtils.getAccessibleField(entity, "isDel");
        Field field2 = ReflectionUtils.getAccessibleField(entity, "delete");

        if(null != field) {
            ReflectionUtils.setFieldValue(entity,"isDel",1);
        }
        if(null != field2) {
            ReflectionUtils.setFieldValue(entity,"delete",1);
        }

        baseBiz.updateSelectiveById(entity);
        return ObjectRestResponse.succ();
    }


    @RequestMapping(value = "baseDetail",method = RequestMethod.GET)
    @ResponseBody
    public ObjectRestResponse<Entity> baseDetail(Entity entity){
        Object o = baseBiz.selectOne(entity);
        return ObjectRestResponse.succ(o);
    }

    @RequestMapping(value = "baseAdd",method = RequestMethod.POST)
    @ResponseBody
    public ObjectRestResponse<Entity> baseAdd(@RequestBody Entity entity){
        baseBiz.insertSelective(entity);
        return new ObjectRestResponse<Entity>();
    }

    @RequestMapping(value = "baseUpdate",method = RequestMethod.POST)
    @ResponseBody
    public ObjectRestResponse<Entity> baseUpdate(@RequestBody Entity entity){
        baseBiz.updateSelectiveById(entity);
        return new ObjectRestResponse<Entity>();
    }


    @Data
    public static class BaseDetailDTO {
        Integer id;
    }

    public <T>void export(Class<T> classz, Supplier<List<Object>> function, String fileName) throws  Exception {
        HttpServletResponse httpServletResponse = getResponse();
        ExcelWriter writer = ExcelUtil.getWriter(true);
        if(StrUtil.isBlank(fileName)) {
            fileName = System.currentTimeMillis()+ "";
        }

        try {
            //封装表头

            handleHead(classz, writer);
            log.info("======export==== ");

            //处理数据
            List<Object> listObject = function.get();
            List<Map> list = CollUtil.newArrayList();
            for(Object object : listObject) {
                list.add(BeanUtil.beanToMap(object,false, false));
            }
            if (list.size() == 0) {
                Map<String, Object> map = CollUtil.newHashMap();
                for(Field field : classz.getDeclaredFields()) {
                    String value =  AnnotationUtil.getAnnotationValue(field, HeadName.class);
                    writer.addHeaderAlias(field.getName(), "");
                }
                list.add(map);
            }
            log.info("list: {} ", JSONUtil.toJsonStr(list));
            writer.write(list);
            httpServletResponse.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
//            httpServletResponse.setContentType("application/vnd.ms-excel;charset=utf-8");
//            httpServletResponse.setHeader("Content-Disposition","attachment;filename="+ URLEncoder
//                    .encode(fileName+ ".xls","utf-8"));
            httpServletResponse.setHeader("Content-Disposition","attachment;filename="+ new String(fileName.getBytes(), "iso8859-1"));
            writer.flush(httpServletResponse.getOutputStream());
        }catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            throw ex;
        }finally {
            writer.close();
        }
    }

    private <T> void handleHead(Class<T> classz, ExcelWriter writer) {
        if(classz == Object.class) {
            return;
        }else {
            handleHead(classz.getSuperclass(), writer);
        }
        for(Field field : classz.getDeclaredFields()) {
            String value =  AnnotationUtil.getAnnotationValue(field, HeadName.class);
            writer.addHeaderAlias(field.getName(), value);
        }
    }

    private <T> void handleHeadRead(Class<T> classz, Map map) {
        if(classz == Object.class) {
            return;
        }else {
            handleHeadRead(classz.getSuperclass(), map);
        }
        for(Field field : classz.getDeclaredFields()) {
            String value =  AnnotationUtil.getAnnotationValue(field, HeadName.class);
            map.put(value, field.getName());
        }
    }

    public <T> List<T> read(Class<T> beanType, MultipartFile cardExcel) {
        List<String[]> cardDatas = ExcelImport.getExcelData(cardExcel);
        String[] headStrArr = cardDatas.get(0);
        cardDatas.remove(0);
        if (Map.class.isAssignableFrom(beanType)) {
            return CollUtil.newArrayList();
        } else {
            List<T> beanList = CollUtil.newArrayList();

            //中--数
            Map<String, Integer> mapInt = CollUtil.newHashMap();
            for (int i = 0; i < headStrArr.length; i++) {
                mapInt.put(headStrArr[i], i);
            }
            //中--英
            Map<String, String> mapStr = CollUtil.newHashMap();
            handleHeadRead(beanType, mapStr);

            for(String[] data : cardDatas) {
                Map<Integer, Object> dataMap = CollUtil.newHashMap();
                for(int i = 0; i < data.length; i++) {
                    String s = data[i];
                    dataMap.put(i, s);
                }
                Map<String, String> headMap = CollUtil.newHashMap();
                Map<String, Object> map2 = CollUtil.newHashMap();

                for(String keySet : mapStr.keySet()) {
                    map2.put(mapStr.get(keySet), dataMap.get(mapInt.get(keySet)));
                }
                beanList.add(BeanUtil.toBean(map2, beanType));
            }
            return beanList;
        }
    }
}
