/**
 * Copyright &copy; 2021-2026 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
 */
package com.jeeplus.database.datalink.controller;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.jeeplus.core.query.QueryWrapperGenerator;
import com.jeeplus.database.DataSourceConfig;
import com.jeeplus.database.datalink.domain.DataSource;
import com.jeeplus.database.datalink.domain.vo.DataSourceTreeVO;
import com.jeeplus.database.datalink.jdbc.DBPool;
import com.jeeplus.database.datalink.service.DataSourceService;
import com.jeeplus.database.datalink.service.mapstruct.DataSourceWrapper;
import com.jeeplus.sys.utils.DictUtils;
import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.HashSet;
import java.util.List;

/**
 * 数据库连接Controller
 *
 * @author 刘高峰
 * @version 2021-08-06
 */
@RestController
@RequestMapping(value = "/database/datalink/dataSource")
public class DataSourceController {

    @Autowired
    private DataSourceService dataSourceService;
    @Autowired
    private DatabaseIdProvider databaseIdProvider;
    @Autowired
    private DataSourceConfig dataSourceConfig;

    /**查询实体
     */
    @PreAuthorize("hasAnyAuthority('database:datalink:dataSource:view','database:datalink:dataSource:add','database:datalink:dataSource:edit')")
    @GetMapping(value = "queryById")
    public ResponseEntity queryById(String id) {
        return ResponseEntity.ok ( dataSourceService.getById ( id ) );
    }

    @PreAuthorize("hasAuthority('database:datalink:dataSource:list')")
    @GetMapping(value = "list")
    public ResponseEntity list(DataSource dataSource, Page <DataSource> page) throws Exception {
        QueryWrapper <DataSource> queryWrapper = QueryWrapperGenerator.buildQueryCondition (dataSource, DataSource.class);
        IPage <DataSource> result = dataSourceService.page (page, queryWrapper);
        return ResponseEntity.ok (result);
    }


    @GetMapping(value = "treeData")
    public ResponseEntity treeData2() {
        List<DataSourceTreeVO> treeList = Lists.newArrayList();
        List <DataSourceTreeVO> treeRoots = Lists.newArrayList();
        String dbType ;
        try{
            dbType = databaseIdProvider.getDatabaseId( SpringUtil.getBean(javax.sql.DataSource.class));

        }catch (Exception e){
            dbType = "mysql";
        }
        treeRoots.add(new DataSourceTreeVO ("master-parent","默认数据源","0","","host", true));

        treeList.add(new DataSourceTreeVO (dataSourceConfig.primary,"本地数据库","master-parent",dataSourceConfig.primary,"db", dbType));

        List<DataSource> list = dataSourceService.lambdaQuery ().eq ( DataSource::isEnable, true ).list ();
        HashSet <String> set = new HashSet();
        for (int i = 0; i < list.size(); i++) {
            DataSource e = list.get(i);
            treeList.add(new DataSourceTreeVO (e.getId(),e.getName(),e.getHost(),e.getEnName(),"db", e.getType()));
            set.add(e.getHost());
        }
        for (String host : set) {
            treeRoots.add(new DataSourceTreeVO (host,host,"0","","host", true));
        }
        List rootTree = getRootTree(treeRoots,treeList);
        return ResponseEntity.ok ( rootTree );
    }



    private List<DataSourceTreeVO> getRootTree(List<DataSourceTreeVO> rootTrees, List<DataSourceTreeVO> list) {
        List<DataSourceTreeVO> trees = Lists.newArrayList();
        for (DataSourceTreeVO root : rootTrees) {
                trees.add(getChildOfTree(root, list));
        }
        return trees;
    }

    private DataSourceTreeVO getChildOfTree(DataSourceTreeVO area, List<DataSourceTreeVO> areaList) {
        area.setChildren(Lists.newArrayList());
        for (DataSourceTreeVO child : areaList) {
                if (child.getParentId().equals(area.getId())) {
                    area.getChildren().add(getChildOfTree(child, areaList));
                }
        }
        return area;
    }

    /**
     * 保存数据库连接
     */
    @PreAuthorize ("hasAnyAuthority('database:datalink:dataSource:add','database:datalink:dataSource:edit')")
    @PostMapping(value = "save")
    public ResponseEntity save(@Valid @RequestBody DataSource dataSource)  {
        String oldName = "";
        if( StrUtil.isNotBlank(dataSource.getId())){
             oldName = dataSourceService.getById (dataSource.getId()).getEnName();
        }

        String driver = DictUtils.getDictValue(dataSource.getType(), "db_driver","mysql");
        dataSource.setDriver(driver);
        dataSource.setUrl(dataSourceService.toUrl(dataSource.getType(), dataSource.getHost(), dataSource.getPort(), dataSource.getDatabaseName ()));
        //新增或编辑表单保存
        dataSourceService.saveOrUpdate (dataSource);
        if(StrUtil.isNotBlank(oldName)){
            DBPool.getInstance().remove (oldName);
        }
        DBPool.getInstance().addDs ( DataSourceWrapper.INSTANCE.toDTO ( dataSource));
        return ResponseEntity.ok ( "保存数据库连接成功" );
    }


    /**
     * 批量删除数据库连接
     */
    @PreAuthorize("hasAuthority('database:datalink:dataSource:del')")
    @DeleteMapping(value = "delete")
    public ResponseEntity delete(@RequestParam(value = "ids", required = false)String ids) {
        String idArray[] = ids.split(",");
        for (String id : idArray) {
            DataSource dataSource = dataSourceService.getById (id);
            DBPool.getInstance().remove (dataSource.getEnName());
            dataSourceService.removeById ( id );
        }
        return ResponseEntity.ok ( "删除数据库连接成功" );
    }




    /**
     * 验证数据库唯一key是否存在
     * @param oldEnName
     * @param enName
     * @return
     */
    @GetMapping(value = "checkEnName")
    public ResponseEntity<String> checkLoginName(@RequestParam(value = "oldEnName", required = false)String oldEnName, @RequestParam(value = "enName", required = false)String enName) {
        if (enName !=null && enName.equals(oldEnName)) {
            return ResponseEntity.ok ("验证通过!");
        } else if (enName !=null && dataSourceService.lambdaQuery ().eq ( DataSource::getEnName, enName ).one () == null) {
            return ResponseEntity.ok ( "验证通过!" );
        }
        return ResponseEntity.badRequest().body ("数据库连接英文名已存在");
    }

    /**
     * 测试数据库连接
     * @param dataSource
     * @return
     */
    @PostMapping("/test")
    public ResponseEntity test(@RequestBody DataSource dataSource) {
        if (StrUtil.isBlank(dataSource.getType ()) || StrUtil.isBlank(dataSource.getHost ()) || StrUtil.isBlank(dataSource.getDatabaseName ()) || StrUtil.isBlank(dataSource.getUsername ())) {
            return ResponseEntity.badRequest ().body ( "配置信息不全" );
        }
        if (DBPool.getInstance().test(dataSourceService.getDriver(dataSource.getType ()), dataSourceService.toUrl(dataSource.getType (), dataSource.getHost (), dataSource.getPort (), dataSource.getDatabaseName ()), dataSource.getUsername (), dataSource.getPassword ())) {
            return ResponseEntity.ok ("连接成功"  );
        } else {
            return ResponseEntity.badRequest ().body ( "连接失败" );
        }
    }

}
