package com.keyware.shandan.browser.controller;

import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.keyware.shandan.bianmu.entity.DirectoryResource;
import com.keyware.shandan.bianmu.entity.MetadataBasicVo;
import com.keyware.shandan.bianmu.export.DirectoryExport;
import com.keyware.shandan.bianmu.export.ExportCache;
import com.keyware.shandan.bianmu.export.ExportProgress;
import com.keyware.shandan.bianmu.export.MetaTableExport;
import com.keyware.shandan.bianmu.service.MetadataService;
import com.keyware.shandan.browser.entity.FullSearchParam;
import com.keyware.shandan.browser.entity.PageVo;
import com.keyware.shandan.browser.entity.SearchConditionVo;
import com.keyware.shandan.browser.service.FileSearchService;
import com.keyware.shandan.browser.service.MetadataDataService;
import com.keyware.shandan.browser.service.MetadataSearchService;
import com.keyware.shandan.browser.service.SearchService;
import com.keyware.shandan.common.entity.Result;
import com.keyware.shandan.common.util.FileDownload;
import com.keyware.shandan.frame.annotation.AppLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;

/**
 * 组合搜索前端控制器
 *
 * @author Administrator
 * @since 2021/7/1
 */
@RestController
@RequestMapping("/search")
public class SearchController {

    @Autowired
    private SearchService searchService;

    @Autowired
    private MetadataService metadataService;

    @Autowired
    private MetadataDataService metadataDataService;

    @Autowired
    private FileSearchService fileSearchService;

    @Autowired
    private MetadataSearchService metadataSearchService;

    /**
     * 全文检索分页查询
     *
     * @param condition 条件
     * @return -
     */
    @AppLog(operate = "全文检索分页查询")
    @PostMapping("/full")
    public Result<PageVo> fullSearch(SearchConditionVo condition) {

        try {
            return Result.of(searchService.esSearch(condition));
        } catch (IOException e) {
            e.printStackTrace();
            return Result.of(null, false, "数据查询异常");
        }
    }


    /**
     * 测试接口
     *
     * @param condition
     * @return
     */
    @PostMapping("/full/test")
    public Result<PageVo> fullSearchTest(@RequestBody SearchConditionVo condition) {

        try {
            return Result.of(searchService.esSearch(condition));
        } catch (IOException e) {
            e.printStackTrace();
            return Result.of(null, false, "数据查询异常");
        }
    }

    @GetMapping("/metadata/columns")
    public Result<JSONObject> getMetaColumns(String metaTable) {
        QueryWrapper<MetadataBasicVo> qw = new QueryWrapper<>();
        qw.eq("METADATA_NAME", metaTable);
        List<MetadataBasicVo> list = metadataService.list(qw);
        if (list != null && list.size() > 0) {
            MetadataBasicVo basicVo = list.get(0);
            JSONObject json = (JSONObject) JSONObject.toJSON(basicVo);
            json.put("field", getFiledByMetadata(basicVo));
            return Result.of(json);
        }
        return Result.of(null, false);
    }

    /**
     * 查询指定数据资源表的分页数据
     *
     * @param metaID
     * @param page
     * @param size
     * @param orderField
     * @param order
     * @return
     */
    @PostMapping("/metadata/page")
    public Result<PageVo> dataPageByMetadata(String metaID, Integer page, Integer size, String orderField, String order) {
        MetadataBasicVo basicVo = metadataService.getById(metaID);
        if (basicVo != null) {
            Page<HashMap<String, Object>> dataList = metadataService.getDynamicData(basicVo, page, size, orderField, order);
            return Result.of(PageVo.pageConvert(dataList));
        }

        return Result.of(null, false);
    }

    private JSONArray getFiledByMetadata(MetadataBasicVo basicVo) {
        JSONArray jsonArray = new JSONArray();
        basicVo.getMetadataDetailsList().forEach(detail -> {
            jsonArray.addAll(JSONArray.parseArray(detail.getTableColumns()));
        });
        return jsonArray;
    }


    /**
     * 全文检索-检索文件
     *
     * @return 文件结果列表
     */
    @AppLog(operate = "文件全文检索查询")
    @GetMapping("/full/file")
    public Result<Object> searchFile(FullSearchParam param) {

        try {
            return Result.of(fileSearchService.searchFile(param));
        } catch (IOException e) {
            e.printStackTrace();
            return Result.of(null, false, "Elasticsearch 请求异常");
        }
    }

    /**
     * 查询指定数据资源下的数据
     *
     * @param metaId    数据资源ID
     * @param condition 条件项
     * @return 分页列表
     */
    @AppLog(operate = "查询指定数据资源下的数据")
    @PostMapping("/metadata/condition/{metaId}")
    public Result<PageVo> searchDataByMetadata(@PathVariable String metaId, SearchConditionVo condition) {
        MetadataBasicVo metadata = metadataService.get(metaId).getData();
        if (metadata != null) {
            return Result.of(metadataDataService.queryData(metadata, condition));
        }
        return Result.of(new PageVo());
    }

    @PostMapping("/metadata/condition/query")
    public Result<PageVo> searchDataByMetadataTest(@RequestParam String metaId, @RequestBody SearchConditionVo condition) {
        MetadataBasicVo metadata = metadataService.get(metaId).getData();
        if (metadata != null) {
            return Result.of(metadataDataService.queryData(metadata, condition));
        }
        return Result.of(new PageVo());
    }

    @GetMapping("/metadata/condition/get")
    public Result<PageVo> searchDataByMetadata2(@RequestParam String metaId,
                                                @RequestParam(value = "page", defaultValue = "1") int page,
                                                @RequestParam(value = "size", defaultValue = "10") int size) {
        SearchConditionVo condition = new SearchConditionVo();
        condition.setSize(size);
        condition.setPage(page);
        MetadataBasicVo metadata = metadataService.get(metaId).getData();
        if (metadata != null) {
            return Result.of(metadataDataService.queryData(metadata, condition));
        }
        return Result.of(new PageVo());
    }

    @AppLog(operate = "检索数据资源")
    @PostMapping("/metadata/all/page/{directoryId}")
    public Result<Object> searchMetadataPage(@PathVariable String directoryId, SearchConditionVo condition) {
        return Result.of(metadataSearchService.searchByCondition(directoryId, condition));
    }

    /**
     * 图片查询
     * @return
     */
    @GetMapping("/image/page/{dirId}")
    public Result<Object> searchImage(@PathVariable String dirId,
                                      @RequestParam(defaultValue = "") String searchText,
                                      @RequestParam(defaultValue = "1") int pageNo,
                                      @RequestParam(defaultValue = "20") int pageSize) throws IOException {
        return Result.of(fileSearchService.searchImage(dirId, searchText, pageNo, pageSize));
    }

    /**
     * 目录数据导出-创建任务
     *
     * @param directoryId 目录ID
     * @param condition   复杂查询条件
     * @return 导出ID
     */
    @PostMapping("/export/directory/{directoryId}")
    public Result<Object> exportQuery(@PathVariable String directoryId, SearchConditionVo condition, Authentication auth) {
        Assert.notNull(auth, "用户信息认证失败");
        String userId = auth.getPrincipal().toString();
        // 这个逻辑只允许同一个用户同时只能有一个导出任务
        ExportProgress export = ExportCache.getCache(userId, null);
        if (export == null) {
            // 查询数据
            List<DirectoryResource> list = metadataSearchService.searchAllListByCondition(directoryId, condition);
            export = new DirectoryExport(userId, list);
            ExportCache.startExport(export);
        }
        return Result.of(export.getProgress(), !export.isError());
    }

    @PostMapping("/export/metadata/{metaId}")
    public Result<Object> exportMetadata(@PathVariable String metaId, SearchConditionVo condition, Authentication auth) {
        Assert.notNull(auth, "用户信息认证失败");
        MetadataBasicVo metadata = metadataService.getById(metaId);
        Assert.notNull(metadata, "数据资源表不存在");

        String userId = auth.getPrincipal().toString();
        MetaTableExport export = ExportCache.getCache(userId, null);
        if (export == null) {
            MetaTableExport newExport = new MetaTableExport(userId, metadata);
            newExport.setQueryHandler((list) -> list.addAll(metadataDataService.list(metadata, condition)));
            export = newExport;
            ExportCache.startExport(export);
        }

        return Result.of(export.getProgress());
    }

    /**
     * 目录数据导出-查询任务状态
     *
     * @param exportId 导出ID
     * @return 导出ID
     */
    @GetMapping("/export/status/{exportId}")
    public Result<Object> exportStatus(@PathVariable String exportId, Authentication auth) {
        String userId = auth.getPrincipal().toString();
        ExportProgress export = ExportCache.getCache(userId, exportId);
        if (export == null) {
            return Result.of(null, false, "导出任务不存在");
        }
        if (export.isError()) {
            ExportCache.popCache(userId, exportId);
        }
        return Result.of(export.getProgress(), !export.isError());
    }

    /**
     * 目录数据导出-下载
     *
     * @param response HttpServletResponse
     * @param exportId 导出ID
     * @return -
     */
    @GetMapping("/export/download/{exportId}")
    public String exportDownload(HttpServletResponse response, @PathVariable String exportId, Authentication auth) {
        String userId = auth.getPrincipal().toString();
        ExportProgress export = ExportCache.popCache(userId, exportId);
        if (export == null) {
            return "错误：导出任务不存在";
        }
        String path = export.getDownloadPath();
        String downloadName = FileUtil.getName(path);
        File file = new File(path);
        return FileDownload.download(response, file, downloadName, true);
    }

}
