package com.bohuikeji.frame.module.admin.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.SqlRunner;
import com.bohuikeji.frame.module.admin.annotation.InitLog;
import com.bohuikeji.frame.module.admin.annotation.TableKeyField;
import com.bohuikeji.frame.module.admin.base.EntityBase;
import com.bohuikeji.frame.module.admin.base.InterfaceBase;
import com.bohuikeji.frame.module.admin.base.PageTemplateControllerBase;
import com.bohuikeji.frame.module.admin.entity.back.APIEntity;
import com.bohuikeji.frame.module.admin.entity.back.PageEntity;
import com.bohuikeji.frame.module.admin.entity.configure.FieldConf;
import com.bohuikeji.frame.module.admin.entity.configure.KeyAn;
import com.bohuikeji.frame.module.admin.entity.sys.*;
import com.bohuikeji.frame.module.admin.entity.vo.TableDataVo;
import com.bohuikeji.frame.module.admin.entity.web.TableColumn;
import com.bohuikeji.frame.module.admin.entity.web.TableData;
import com.bohuikeji.frame.module.admin.entity.web.block.SelectBlock;
import com.bohuikeji.frame.module.admin.entity.web.template.TableTemplate;
import com.bohuikeji.frame.module.admin.service.IFieldAuthService;
import com.bohuikeji.frame.module.admin.utils.EntityUtils;
import com.bohuikeji.frame.module.admin.utils.ReflectUtil;
import com.bohuikeji.frame.module.admin.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 表格查询统一处理
 * @author 10552
 */
@Slf4j
@RestController
@RequiredArgsConstructor
public class FrameTableController extends PageTemplateControllerBase {

    final IFieldAuthService authService;


    /**
     * 默认表格组合查询方法
     * @param dataVo
     * @return
     */
    @GetMapping("/table/query")
    public InterfaceBase toQueryPage(TableDataVo dataVo){
        EntityBase entity=crateActiveEntity();
        if (entity==null){
            return APIEntity.fail();
        }
        return TableData.success(entity.selectPage(getPage(dataVo),createQueryAndSearchByParam(dataVo.getQuery(),dataVo.getSearch())));
    }

    /**
     * 弹出层表单默认提交方法
     * @return
     */
    @InitLog("系统框架——表单提交")
    @PostMapping("/table/model/form")
    public InterfaceBase formSubmit(HttpServletRequest request,@RequestParam Map<String,String> params){
        EntityBase entityBase=crateEntityByMap(params);
        SysLog sysLog=getLog(request);
        //id为空，新增
        sysLog.setLogAction(StringUtils.isBlank(entityBase.forIdField().getName())?"新增":"修改");

        if(entityBase.insertOrUpdate()){
            sysLog.setLogDetail(StringUtils.formatStr("更改[{0}]中的[{1}]，参数为：{2}",sysLog.getLogMenu(),JSON.toJSONString(entityBase),JSON.toJSONString(params)));
            return APIEntity.success();
        }
        return APIEntity.fail("系统繁忙，请稍后再试！");
    }

    /**
     * 删除
     * @param
     * @return
     */
    @InitLog(value = "系统框架——数据删除",action = "删除")
    @PostMapping("/table/button/delete")
    public InterfaceBase delete(HttpServletRequest request, @RequestParam("idsp[]") Integer[] ids){
        EntityBase entity=crateActiveEntity();
        if (entity==null){
            return APIEntity.fail();
        }
        List<EntityBase> list= entity.selectList(new QueryWrapper<>().in(entity.forIdColumn(),ids));
        if(entity.delete(new QueryWrapper<>().in(entity.forIdColumn(),ids))){
            //补充日志
            getLog(request).setLogDetail(StringUtils.formatStr("删除以下数据：{0}，共计[{1}]条", JSON.toJSONString(list),list.size()));
            return APIEntity.success();
        }
        return APIEntity.fail("系统繁忙，请稍后再试！");
    }

    /**
     * 导出Excel
     * @param ids
     * @param response
     * @return
     */
    @GetMapping("/table/export/excel")
    public APIEntity export(Integer[] ids, HttpServletResponse response){
        try {
            exportExcel(ids,response);
        } catch (IOException e) {
            return APIEntity.fail("导出失败~~");
            //e.printStackTrace();
        }
        return APIEntity.success();
    }
    /**
     * 搜索下拉框搜索接口
     * @return
     */
    @PostMapping("/block/select/search")
    public APIEntity selectLike(@RequestBody SelectBlock block){
        String sql= null;
        try {
            sql = "select "+ EntityUtils.getTableKey(block.getKeyTableName())+" as id"
                    +","+ StringUtils.join(block.getKeyShowName(),",")
                    +" from "+block.getKeyTableName()
                    +" where 1=1 and "
                    + block.getKeyLikeName()[0]+" like "
                    +" '"+(block.getSearchKey()==null?"":block.getSearchKey().replaceAll(StringUtils.regEx,""))+"%'"
                    +("".equals(block.getKeyWhere())?"": " and "+authService.formartSql(URLDecoder.decode(block.getKeyWhere(),"UTF-8"),getLoginUser()))
                    +" order by id desc"
                    +" limit 20";
        } catch (UnsupportedEncodingException e) {
            log.error("参数:[{}]解码错误",block.getKeyWhere(),e);
            return APIEntity.fail("参数解码错误");
        }
        /*for(String columnName:block.getKeyLikeName()){
            columnName+" like"
        }*/
        List<Map<String,Object>>res=new SqlRunner(SysRole.class).selectList(sql);
        return APIEntity.success(res);
    }
    /**
     * 搜索下拉框搜索回显接口
     * @return
     */
    @PostMapping("/block/select/search/back/id")
    public APIEntity<Map<String,Object>> selectById(String keyTableName,Integer id){
        if(StringUtils.isBlank(id+"")||id==0){
            log.warn("外键字段为空，table=[{}],ID=[{}]",keyTableName,id);
            return APIEntity.fail("外键为空！");
        }
        String sql="select *,"+EntityUtils.getTableKey(keyTableName)+" as id"
                +" from "+keyTableName+" where "+EntityUtils.getTableKey(keyTableName)+"={0}";
        Map<String,Object> res=new SqlRunner(SysRole.class).selectOne(sql,id);
        if(res==null||res.size()<1){
            log.error("【搜索下拉框搜索回显接口异常】无法找到外键数据，Sql=[{}]，ID=[{}]",sql,id);
            SysError.saveError("[外键关联数据丢失]执行sql：{0}，参数：{1}",sql,id);
            return APIEntity.fail("无法找到该条数据！");
        }
        return APIEntity.success(res);
    }
    /**
     * 表格数据区域外键关联查询
     * @return
     */
    @GetMapping("/block/select/search/show/id")
    public APIEntity selectActiveById(String fieldName,Integer id,String key){
        if(id==null||id==0){
            return APIEntity.success("-");
        }
        SysPage page=(SysPage) session.getAttribute("activePage");
        if(page!=null){
            KeyAn keyAn=null;
            for(FieldConf fieldConf:page.getPageConf().getFieldConfs()){
                if(fieldConf.getFieldName().equals(fieldName)){
                    keyAn=fieldConf.getKey();
                }
            }
            if (keyAn==null){
                log.error("外键无法识别");
                return APIEntity.fail("系统配置错误，请联系管理员！");
            }
            String key_table_name=keyAn.getTable();
            if(StringUtils.isBlank(key_table_name)){
                log.error("外键无法识别，请为[{}.{}]字段配置TableKeyField注解，并设置'table()'属性");
                return APIEntity.fail("系统配置错误，请联系管理员！");
            }
            Map<String,Object> res=new SysUser().sql().selectOne("select "+StringUtils.join(keyAn.getKeyShowFields(),",")+" from "+key_table_name+" where "+EntityUtils.getTableKey(key_table_name)+"={0}",id);
            if (res==null){
                //log.error("【数据错误】无法找到外键关联数据，位于[{}.{}]关联至[{}]键值为[{}]",entity.getClass(),fieldName,key_table_name,id);
                //如外键无值，返回默认
                return APIEntity.success("-");
            }
            StringBuilder str=new StringBuilder();
            for (String column:keyAn.getKeyShowFields()){
                str.append(res.get(column));
                str.append(keyAn.getSplit());
            }
            str.delete(str.lastIndexOf(keyAn.getSplit()),str.length()+1);
            return APIEntity.success(str.toString());
        }
        else {
            EntityBase entity=StringUtils.isNotBlank(key)?crateEntityByName(key):crateActiveEntity();
            Field field=crateField(entity,fieldName);
            TableKeyField keyField=field.getAnnotation(TableKeyField.class);
            if (keyField==null){
                log.error("外键无法识别，请为[{}.{}]字段配置TableKeyField注解",entity.getClass(),fieldName);
                return APIEntity.fail("系统配置错误，请联系管理员！");
            }
            String key_table_name=keyField.table();
            if("".equals(key_table_name)){
                key_table_name= ReflectUtil.getTableName(keyField.key());
                log.warn("不推荐使用@TableKeyField注解中的的key()属性配置外键，请改用table()配置。位于：[{}.{}]",entity.getClass(),fieldName);
            }
            if(StringUtils.isBlank(key_table_name)){
                log.error("外键无法识别，请为[{}.{}]字段配置TableKeyField注解，并设置'table()'属性",entity.getClass(),fieldName);
                return APIEntity.fail("系统配置错误，请联系管理员！");
            }
            Map<String,Object> res=entity.sql().selectOne("select "+StringUtils.join(keyField.keyShowFields(),",")+" from "+key_table_name+" where "+EntityUtils.getTableKey(key_table_name)+"={0}",id);
            if (res==null){
                log.error("【数据错误】无法找到外键关联数据，位于[{}.{}]关联至[{}]键值为[{}]",entity.getClass(),fieldName,key_table_name,id);
                //如外键无值，返回默认
                return APIEntity.success("-");
            }
            StringBuilder str=new StringBuilder();
            for (String column:keyField.keyShowFields()){
                str.append(res.get(column));
                str.append(keyField.symbol());
            }
            str.delete(str.lastIndexOf(keyField.symbol()),str.length()+1);
            return APIEntity.success(str.toString());
        }
    }

    /**
     * 获取session弹出框组件配置
     * @return
     */
    @GetMapping("/table/model/get/template")
    public APIEntity getPageTemplate(){
        return APIEntity.success(((TableTemplate)session.getAttribute("pageTemplate")).getTableModel());
    }

    /**
     * 查询实体指定段值
     * @param id
     * @param column
     * @return
     */
    /*@GetMapping("/table/model/get/column")
    public APIEntity getColumn(Integer id,String column){
        EntityBase entity=crateActiveEntity();
        String sql="select "+column+ " from "+ReflectUtil.getTableName(entity.getClass())+" where "+entity.forIdColumn()+"={0}";
        return APIEntity.success(entity.sql().selectObj(sql,id));
    }*/

    /**
     * 更改实体指定字段
     * @param id
     * @param column
     * @param value
     * @return
     */
    @InitLog(value = "系统框架——字段更新",action = "修改")
    @PostMapping("/table/model/set/column")
    public APIEntity setColumn(HttpServletRequest request,Integer id,String column,String value){
        EntityBase entity=crateActiveEntity();
        SqlRunner runner=entity.sql();
        if(runner.update("update "+entity.forDbTableName()+" set "+column+"={0} where "+entity.forIdColumn()+"={1}",value,id)){
            SysLog sysLog=getLog(request);
            sysLog.setLogDetail(StringUtils.formatStr("将ID=[{0}]的[{1}]记录修改[{2}]=[{3}]",id+"",sysLog.getLogMenu(),entity.forExplainByColumn(column),value));
            return APIEntity.success();
        }
        return APIEntity.fail("系统繁忙，请稍后再试！");
    }

    @GetMapping("/component/page/id")
    public PageEntity test(Integer id,String className){
        EntityBase model=crateEntityByName(className);
        session.setAttribute("pageTemplate",createPage(TableTemplate.class));
        return PageEntity.page("/table/index").add("Model",model.forTableModel());
    }

    /**
     * 数组外键获取数据
     * @param dataVo
     * @return
     */
    @GetMapping("/table/key/query/model/array")
    public InterfaceBase queryArrayTableKey(TableDataVo dataVo) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException, NoSuchFieldException, InstantiationException {
        EntityBase entity=(EntityBase) crateActiveEntity().selectById(dataVo.getQuery().get("id"));
        String fieldName=dataVo.getQuery().get("field");
        Object obj=entity.queryValueByFieldName(fieldName);
        QueryWrapper<EntityBase> queryWrapper=new QueryWrapper<>();
        TableKeyField keyField=entity.getClass().getDeclaredField(fieldName).getDeclaredAnnotation(TableKeyField.class);
        EntityBase keyEntity=keyField.key().newInstance();
        if(obj instanceof String[]){
            //获取外键ID值
            String[] value=(String[])obj;
            queryWrapper.in(keyEntity.forIdColumn(),value);
        }else {
            queryWrapper.eq(keyEntity.forIdColumn(),obj);
        }
        return TableData.success(keyEntity.selectPage(new Page(dataVo.getOffset(),dataVo.getPageSize()),queryWrapper));
    }

    /**
     * 获取外键table表配置
     * @param id 数据id
     * @param fieldName 字段名
     * @return
     */
    @GetMapping("/table/key/model/conf")
    public APIEntity<List<JSONObject>> modelConf(String fieldName){
        EntityBase entity=(EntityBase) crateActiveEntity();
        Field field= null;
        try {
            field = entity.getClass().getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            return APIEntity.fail("暂无信息！");
        }
        TableKeyField keyField=field.getDeclaredAnnotation(TableKeyField.class);
        EntityBase keyEntity=crateEntityByName(keyField.key().getName());
        List<TableColumn> tableColumns=keyEntity.forTableColumn();
        List<JSONObject> columns=new ArrayList<>(tableColumns.size());
        tableColumns.forEach(t->{
            JSONObject cf=new JSONObject();
            cf.put("field",t.getDataField());
            cf.put("title",t.getDataTitle());
            cf.put("key",keyField.key().getName());
            cf.put("formatter",t.getDataFormatter());
            columns.add(cf);
        });
        return APIEntity.success(columns);
    }







}
