package com.search.supersearch.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.json.JSONUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.indices.CreateIndexResponse;
import co.elastic.clients.elasticsearch.indices.DeleteIndexResponse;
import co.elastic.clients.transport.endpoints.BooleanResponse;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.search.supersearch.common.R;
import com.search.supersearch.domain.DwdNocFilesEs;
import com.search.supersearch.domain.IamSearchCategoryidIndexname;
import com.search.supersearch.mapper.pgsql.CustomMapper;
import com.search.supersearch.model.pojo.DocsIndex;
import com.search.supersearch.model.pojo.SearchType;
import com.search.supersearch.service.EsService;
import com.search.supersearch.service.OssService;
import com.search.supersearch.service.mysql.IamSearchCategoryidIndexnameService;
import com.search.supersearch.service.pgsql.DwdNocFilesEsService;
import com.search.supersearch.util.FileUtil;
import io.swagger.annotations.Api;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Date;
import java.util.*;

/**
 * @author wangrui
 */
@RestController
@RequestMapping("/es")
@Slf4j
@Api(value = "es 数据初始化", tags = "es 数据初始化")
public class EsInitController {
    @Resource
    CustomMapper customMapper;
    @Resource
    private ElasticsearchClient elasticsearchClient;
    @Resource
    private EsService esService;
    @Resource
    private IamSearchCategoryidIndexnameService iamSearchCategoryidIndexnameService;
    @Resource
    private OssService ossService;
    @Value("${oss.bucketName}")
    private String bucket_name;
    @Resource
    private DwdNocFilesEsService dwdNocFilesEsService;

    @Value("${spring.datasource.dynamic.datasource.dws_7tzly_test.username}")
    private String USER;
    @Value("${spring.datasource.dynamic.datasource.dws_7tzly_test.password}")
    private String PASSWORD;
    @Value("${spring.datasource.dynamic.datasource.dws_7tzly_test.url}")
    private String JDBC_URL;

    @GetMapping("/run")
    @SneakyThrows
    @Deprecated
    public R<?> run() {
        Page<DwdNocFilesEs> page = dwdNocFilesEsService.lambdaQuery()
                .eq(DwdNocFilesEs::getTrans2es, 0)
                .page(new Page<>(1, 10));
        List<DwdNocFilesEs> records = page.getRecords();
        return R.data(JSONUtil.toJsonStr(page));
    }

    //    @GetMapping("/delete")
    @SneakyThrows
    public R<?> delete(String[] index) {
        DeleteIndexResponse deleteIndexResponse = elasticsearchClient.indices()
                .delete(deleteIndexRequest ->
                        deleteIndexRequest.index(Lists.newArrayList(index))
                );

        return R.data("jieshu");
    }

    @GetMapping("/delete/v3")
    @SneakyThrows
    public R<?> deletev2(String[] index) {
        try {
            DeleteIndexResponse deleteIndexResponse = elasticsearchClient.indices()
                    .delete(deleteIndexRequest ->
                            deleteIndexRequest.index(Lists.newArrayList(index))
                    );
            log.info("成功删除={}", index);
        } catch (Exception e) {
            log.info("失败删除={}", index);
        }

        return R.data("jieshu");
    }

    @GetMapping("/init/file/v3/list")
    @SneakyThrows
    public R<?> initv3List(String[] names, String oss) {
        log.info("es data file init ");
        for (String name : names) {
            initFilev3(name, oss);
        }
        log.info("jieshu");
        return R.data("jieshu");
    }

    /**
     * 0.文件待入库
     * 1.正常文件
     * 2. url==null
     * 3.不能解压的压缩文件
     * 4.localOssProcessor文件不存在
     * 5.tika解析异常
     * 6.压缩包文件
     *
     * @param name
     * @param oss
     * @return {@link R<?>}
     * @author 王瑞
     * @date 2024/1/25
     */
    @GetMapping("/init/file/v3")
    @SneakyThrows
    public R<?> initFilev3(String name, String oss) {
        log.info("es data file init ");
        List<SearchType> searchType = FileUtil.getSearchType("index/es索引-" + name + ".json");
        for (int i = 1; i < searchType.size(); i++) {
            SearchType type = searchType.get(i);
            IamSearchCategoryidIndexname one = null;
            one = iamSearchCategoryidIndexnameService.lambdaQuery().eq(IamSearchCategoryidIndexname::getIndexName, type.getIndexName()).one();
            if (one == null) {
                one = new IamSearchCategoryidIndexname();
                BeanUtil.copyProperties(type, one);
                iamSearchCategoryidIndexnameService.save(one);
            }
            if (type.getDeleteIndex() == 0) {
                String index = one.getIndexName();
                BooleanResponse booleanResponse = elasticsearchClient.indices()
                        .exists(existsRequest ->
                                existsRequest.index(Lists.newArrayList(index))
                        );
                log.info("== {} 索引创建是否存在: {}", index, booleanResponse.value());
                if (booleanResponse.value()) {
                    deleteIndex(one);
                }
                createIndex(one, type.getNumberOfShards(), type.getNumberOfReplicas());

            }
            hadnle(type.getOrgCodeFiled(), one, oss);
        }

        log.info("jieshu");
        return R.data("jieshu");
    }

    private void hadnle(String org, IamSearchCategoryidIndexname byId, String oss) throws Exception {
        // 偏移量初始化为0
        int pageNum = 1;
        // 每页大小初始化为500
        int size = 5000;
        String[] split = null;
        List<HashMap<String, String>> extracted = null;
        StringBuilder tableRemark = new StringBuilder();
        if (byId.getType() == 1) {

            String indexSource = byId.getIndexSource();
            split = indexSource.split("\\.");
            extracted = extracted(split[0], split[1], tableRemark);


        }


        while (true) {
            log.info("pageNum={},size={}", pageNum, size);
            List records = null;
            Long total = 0L;

            //执行非结构化导入
            if (byId.getType() == 0) {
                records = handleFile(byId, 1, size, oss);
            }
            //执行结构化导入
            if (byId.getType() == 1) {
                records = handleTable(pageNum, size, byId, org, total, split[0], split[1], extracted, tableRemark.toString());
            }


            if (records == null) {
                total = 0L;
                break;
            }

            // (2)判断userList的大小是否小于每页大小，如果小于则跳出循环
            if (records.size() < size) {
                total = 0L;
                break;
            }
            pageNum++;
        }
    }

    private String deleteIndex(IamSearchCategoryidIndexname byId) throws IOException {
        String index = byId.getIndexName();
        DeleteIndexResponse deleteIndexResponse = elasticsearchClient.indices()
                .delete(deleteIndexRequest ->
                        deleteIndexRequest.index(Lists.newArrayList(index))
                );
        log.info("== {} 索引创建是否删除成功: {}", index, deleteIndexResponse.acknowledged());
        return index;
    }

    private String createIndex(IamSearchCategoryidIndexname byId, String numberOfShards, String numberOfReplicas) throws IOException {
        String index = byId.getIndexName();


        CreateIndexResponse createIndexResponse = elasticsearchClient.indices()
                .create(createIndexRequest ->
                        createIndexRequest.index(index).settings(s -> s.numberOfReplicas(numberOfReplicas).numberOfShards(numberOfShards))
                );
        log.info("== {} 索引创建是否成功: {}", "elasticsearch-client", createIndexResponse.acknowledged());
        return index;
    }

    private List handleTable(int pageNum, int size, IamSearchCategoryidIndexname byId, String org, Long total, String schema, String table, List<HashMap<String, String>> extracted, String tableRemark) throws Exception {

        customMapper.setschema_name(schema);
        if (total < 1) {
            total = customMapper.count(table);
        }
        List<Map> records = customMapper.selectUserByNameAndAge(table, new Page(pageNum, size));
        // （1）判断userList是否为空，如果为空则跳出循环
        if (records == null || records.isEmpty()) {
            return null;
        }
        // 业务逻辑处理
//            for (DwdNocFilesEs record : records) {
        for (int i = 0; i < records.size(); i++) {
            Map record = records.get(i);
            log.info("处理数据index={},total={},page={},i={},", byId.getIndexName(), total, pageNum, i);
            if (record == null) {
                continue;
            }

            HashMap<@Nullable Object, @Nullable Object> map = Maps.newHashMap();

            StringBuilder stringBuilder = new StringBuilder();
            for (Object key : record.keySet()) {
                stringBuilder.append(record.get(key)).append("|");
                HashMap<String, String> map1 = extracted.stream().filter(v -> v.get("COLUMN_NAME").equalsIgnoreCase(key.toString())).findAny().orElse(Maps.newHashMap());
                if (StringUtils.isNotBlank(map1.get("REMARKS"))) {
                    map.put(map1.get("REMARKS"), record.get(key));
                } else {
                    map.put(key, record.get(key));
                }
            }
            //遍历map中的值
            for (Object value : record.values()) {
                stringBuilder.append(value).append("|");
            }
            if (StringUtils.isEmpty(org)) {
                throw new Exception("table数据不合法!orgid 为空!");
            }
            DocsIndex docsIndex = new DocsIndex();
            docsIndex.setEs_data_content(stringBuilder.toString());
            docsIndex.setEs_data_simple_content(stringBuilder.toString());

            if (StringUtils.isNotEmpty(stringBuilder.toString()) && stringBuilder.toString().length() > 300) {
                docsIndex.setEs_data_simple_content(stringBuilder.substring(0, 200));
            }
            docsIndex.setEs_data_source(byId.getSystemName());
            docsIndex.setEs_data_type("1");
            docsIndex.setEs_data_title(table);
            if (StringUtils.isNotEmpty(tableRemark)) {
                docsIndex.setEs_data_title(tableRemark);
            }
            docsIndex.setEs_data_time(new Date() + "");
            Date dsjsj_update = (Date) record.get("dsjsj_update");
            if (dsjsj_update!=null){
                docsIndex.setEs_order_time(dsjsj_update);
            }else {
                docsIndex.setEs_order_time(new Date());
            }
            docsIndex.setEs_fileId(IdUtil.fastSimpleUUID());
            docsIndex.setEs_index_creat_date(new Date());
            docsIndex.setEs_index_name(byId.getIndexName());
            docsIndex.setEs_ord_id(record.get(org) + "");


            docsIndex.setData(BeanUtil.beanToMap(map));
            esService.saveFile(byId.getIndexName(), docsIndex);
        }
        return records;
    }

    private List<HashMap<String, String>> extracted(String schema, String tableNamePattern, StringBuilder tableRemark) throws SQLException {
        Properties props = new Properties();
        props.put("user", USER);
        props.put("password", PASSWORD);
        props.put("loginTimeout", 10000);
        props.put("connectTimeout", 10000);
        props.put("socketTimeout", 10000);
        props.put("remarks", true);
        Connection connection = null;
        connection = DriverManager.getConnection(JDBC_URL, props);
        DatabaseMetaData metaData = connection.getMetaData();

        ResultSet rs = metaData.getColumns(null, schema, tableNamePattern, "%");
        List<HashMap<String, String>> sourceCloumn = new ArrayList<>();

        while (rs.next()) {
            HashMap<String, String> map = new HashMap<>();
            map.put("REMARKS", rs.getString("REMARKS"));
            map.put("COLUMN_NAME", rs.getString("COLUMN_NAME"));
            sourceCloumn.add(map);
        }

        ResultSet rs2 = metaData.getTables(null, schema, tableNamePattern, new String[]{"TABLE", "VIEW"});

        while (rs2.next()) {
            String remarks = rs2.getString("REMARKS");
            if (StringUtils.isNotEmpty(remarks)) {
                tableRemark.append(remarks);
            }
        }
        connection.close();
        return sourceCloumn;
    }

    private List handleFile(IamSearchCategoryidIndexname byId, int pageNum, int size, String oss) throws Exception {
        Page<DwdNocFilesEs> page = dwdNocFilesEsService.lambdaQuery()
                .eq(DwdNocFilesEs::getSystemid, byId.getSystemId())
                .eq(DwdNocFilesEs::getTrans2es, 0)
                .page(new Page<>(pageNum, size));
        List<DwdNocFilesEs> records = page.getRecords();
        // （1）判断userList是否为空，如果为空则跳出循环
        if (records == null || records.isEmpty()) {
            return null;
        }
        // 业务逻辑处理
//            for (DwdNocFilesEs record : records) {
        for (int i = 0; i < records.size(); i++) {
            try {
                DwdNocFilesEs record = records.get(i);
                log.info("处理文件index={},total={},page={},i={},filename={}", byId.getIndexName(), page.getTotal(), pageNum, i, record.getOssFileFullPath());

                Integer trans2es = 1;

                if (StringUtils.isEmpty(oss)) {
                    trans2es = urlProcessor(byId, record);
                } else {
                    trans2es = localOssProcessor(byId, record);
                }
                record.setTrans2es(trans2es);
                dwdNocFilesEsService.updateById(record);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return records;
    }

    private Integer localOssProcessor(IamSearchCategoryidIndexname byId, DwdNocFilesEs record) throws Exception {
        File file = new File("/data/oss_data/" + record.getOssFileFullPath());
        if (!file.exists()) {
            log.error("文件不存在!file={}", file.getPath());
            return 4;
        }
        return saveESFileData(file, byId, record);
    }

    private Integer urlProcessor(IamSearchCategoryidIndexname byId, DwdNocFilesEs record) throws Exception {
        URL url = getUrl(record);
        if (url == null) {
            return 2;
        }
        File file = new File("./tmp/tmp_" + IdUtil.fastSimpleUUID());
        FileUtils.copyURLToFile(url, file);

        Integer integer = saveESFileData(file, byId, record);
        if (file.exists()) {
            file.delete();
        }
        return integer;
    }

    private Integer saveESFileData(File file, IamSearchCategoryidIndexname byId, DwdNocFilesEs record) throws Exception {
        if (isCompressedFile(file.getName())) {
            try {
                //将test.zip解压到e:\\aaa目录下，返回解压到的目录
                File unzip = ZipUtil.unzip(file.getPath(), "./zip_tmp" + IdUtil.fastSimpleUUID(), CharsetUtil.CHARSET_GBK);
                func(unzip, byId, record);
                if (unzip.exists()) {
                    cn.hutool.core.io.FileUtil.del(unzip);
                }
            } catch (Exception e) {
                log.error("不能解压的压缩文件={}", file.getPath());
                return 3;
            }
            return 6;

        }
        return esService.saveFile(file, byId.getIndexName(), record);

    }

    private void func(File file, IamSearchCategoryidIndexname byId, DwdNocFilesEs record) throws Exception {
        File[] fs = file.listFiles();
        for (File f : fs) {
            if (f.isDirectory())    //若是目录，则递归打印该目录下的文件
            {
                func(f, byId, record);
            }
            if (f.isFile())        //若是文件，直接打印
            {
                saveESFileData(f, byId, record);
            }
        }
    }

    private boolean isCompressedFile(String fileName) {
        String extension = fileName.substring(fileName.lastIndexOf(".") + 1);
        return extension.equalsIgnoreCase("zip") ||
                extension.equalsIgnoreCase("rar") ||
                extension.equalsIgnoreCase("7z");
    }

    @GetMapping("/ossFiledownload")
    @SneakyThrows
    public R<?> ossFiledownload() {
        log.info("ossFiledownload start");

        // 偏移量初始化为0
        int pageNum = 1;
        // 每页大小初始化为500
        int size = 5000;
        while (true) {
            log.info("pageNum={},size={}", pageNum, size);
            Page<DwdNocFilesEs> page = dwdNocFilesEsService.lambdaQuery().eq(DwdNocFilesEs::getTrans2es, 0).page(new Page<>(pageNum, size, false));
            List<DwdNocFilesEs> records = page.getRecords();
            // （1）判断userList是否为空，如果为空则跳出循环
            if (records == null || records.isEmpty()) {
                break;
            }
            for (int i = 0; i < records.size(); i++) {
                DwdNocFilesEs record = records.get(i);
                URL url = getUrl(record);
                log.info("处理文件i={},filename={}", i, record.getOssFileFullPath());
                if (url == null) {
                    continue;
                }
                File f = new File("./ossFiledownload/" + record.getOssFileFullPath());
                FileUtils.copyURLToFile(url, f);
            }

            // (2)判断userList的大小是否小于每页大小，如果小于则跳出循环
            if (records.size() < size) {
                break;
            }
            pageNum++;
        }
        log.info("ossFiledownload end");
        return R.data("jieshu");
    }

    private URL getUrl(DwdNocFilesEs record) {
        return ossService.getOssObjectUrl(record.getOssFileFullPath(), ossService.restOSSClient());
    }
}
