/**
 * 
 */
package org.springblade.etl.controller;

import java.io.InputStream;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Stream;

import org.apache.commons.io.FilenameUtils;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.support.Kv;
import org.springblade.datasource.constants.CubeConstants;
import org.springblade.etl.connector.source.PlatomixFtpFileSource;
import org.springblade.etl.dto.FileStructure;
import org.springblade.etl.properties.SftpProperties;
import org.springblade.etl.util.CubeExcelAnalysisEventListener;
import org.springblade.etl.util.CubeUtils;
import org.springblade.etl.util.ExcelReadLimitException;
import org.springblade.etl.util.FtpUtil;
import org.springblade.etl.util.SftpUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.support.ExcelTypeEnum;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;

/**
 * @author wookvn
 *
 */
@Slf4j
@RestController
@RequestMapping("/file-upload")
@Api(value = "文件上传相关接口", tags = "文件上传接口")
public class FileUploadController extends BladeController {
	
	@Autowired
	private SftpProperties sftpConfig;
	
	/**
	 * 文件结构
	 * 
	 * @param file
	 * @return
	 * @throws Exception
	 */
	@PostMapping("/structure")
	@ApiOperation(value = "上传文件并获取结构接口[获取结构仅支持csv和excel]")
	public R<Kv> fileStructure(MultipartFile file, String sheetName) {
		if(file == null || file.getSize() <= 0) {
			return R.fail("文件必须上传");
		}
		// 1.读取并解析excel文件
		String extension = FilenameUtils.getExtension(file.getOriginalFilename());
		if (!Stream.of(CubeConstants.SUPPORTS_FILE).anyMatch(f -> f.equalsIgnoreCase(extension))) {
			return R.fail(String.format("文件只支持%s格式", String.join(",", CubeConstants.SUPPORTS_FILE)));
		}
		Kv result = Kv.create();
		//上传文件到sftp服务器
		String tempFileName = UUID.randomUUID().toString() + "." + extension;
		SftpUtil sftp = new SftpUtil(sftpConfig.getUser(), sftpConfig.getPassword(), sftpConfig.getHost(), sftpConfig.getPort());
        try {
			sftp.login();
			sftp.upload(sftpConfig.getUploadDir(), tempFileName, file.getInputStream());
//			FileUtils.copyInputStreamToFile(file.getInputStream(), cubeFile);
//			File cubeFile = FileKit.createFile(Paths.get(sftpConfig.getUploadDir(), tempFileName)).toFile();
			result.set("path", Paths.get(sftpConfig.getUploadDir(), tempFileName).toString());
			if("xls".equalsIgnoreCase(extension) || "xlsx".equalsIgnoreCase(extension) || "csv".equalsIgnoreCase(extension)) {
				List<Map<Integer, String>> dataList = new ArrayList<Map<Integer, String>>();
				CubeExcelAnalysisEventListener analysisEventListener = new CubeExcelAnalysisEventListener(CubeConstants.DEFAULT_READ_EXCEL_SIZE, false, dataList::addAll);
				try {
					// 读取部分数据
					ExcelReader excelReader = EasyExcel.read(file.getInputStream(), analysisEventListener).excelType(ExcelTypeEnum.valueOf(extension.toUpperCase())).build();
					if(StrUtil.isBlank(sheetName)) {
						List<ReadSheet> sheets = excelReader.excelExecutor().sheetList();
						result.set("sheets", sheets);
					}
					excelReader.read(new ReadSheet(null, StrUtil.isNotBlank(sheetName) ? sheetName : null));
					excelReader.finish();
				} catch (Exception e) {
					if (e.getCause() instanceof ExcelReadLimitException || e instanceof ExcelReadLimitException) {
					} else {
						log.error(e.getMessage(), e);
					}
				}
				// 表头数据
				Map<Integer, String> headDataMap = analysisEventListener.getHeadMap();
				List<FileStructure> fileStructList = new ArrayList<FileStructure>();
				// 表头和数据集不为空
				if (headDataMap != null && !headDataMap.isEmpty() && !dataList.isEmpty()) {
					headDataMap.forEach((k, v) -> {
						FileStructure fileStructure = new FileStructure();
						fileStructure.setColumnName(CubeConstants.COLUMN_NAME_PREFIX + k);
						fileStructure.setColumnType(CubeUtils.resolveDataType(k, dataList));
						fileStructure.setComment(v);
						fileStructure.setColumnIndex(k);
						fileStructList.add(fileStructure);
					});
				}
				result.set("fields", fileStructList);
			}
		} catch (Exception ex) {
			log.error(ex.getMessage(), ex);
		} finally {
			sftp.logout();
		}
		return R.data(result);
	}

	/**
	 * 读取sftp中的文件结构
	 * @param path
	 * @param sheetName
	 * @return
	 * @throws Exception
	 */
	@PostMapping("/readStructure/{ftpType}")
	@ApiOperation(value = "获取ftp/sftp服务器上文件的结构接口[获取结构仅支持csv和excel]")
	@ApiImplicitParam(name = "ftpType", value = "ftp类型[ftp/sftp]", required = true, paramType = "path")
	public R<Kv> readStructure(@PathVariable String ftpType, @RequestBody PlatomixFtpFileSource.Config config) {
		String extension = FilenameUtils.getExtension(config.getPath());
		if (!"xls".equalsIgnoreCase(extension) && !"xlsx".equalsIgnoreCase(extension) && !"csv".equalsIgnoreCase(extension)) {
			return R.fail("暂不支持读取"+extension+"类型文件结构");
		}
		config.setHost(Optional.<String>ofNullable(config.getHost()).orElse(sftpConfig.getHost()));
		config.setUser(Optional.<String>ofNullable(config.getUser()).orElse(sftpConfig.getUser()));
		config.setPort(Optional.<Integer>ofNullable(config.getPort()).orElse(sftpConfig.getPort()));
		config.setPassword(Optional.<String>ofNullable(config.getPassword()).orElse(sftpConfig.getPassword()));
		InputStream is = null;
		if("sftp".equalsIgnoreCase(ftpType)) { //sftp
			SftpUtil sftp = new SftpUtil(config.getUser(), config.getPassword(), config.getHost(), config.getPort());
	        try {
				sftp.login();
				is = sftp.read(config.getPath());
			} catch (Exception e) {
				log.error(e.getMessage(), e);
			} finally {
				sftp.logout();
			}
		}else {//ftp
			FtpUtil ftpUtil = new FtpUtil();
			try {
				ftpUtil.login(config.getUser(), config.getPassword(), config.getHost(), config.getPort());
				is = ftpUtil.read(config.getPath());
			} catch (Exception e) {
				log.error(e.getMessage(), e);
			} finally {
				ftpUtil.logout();
			}
		}
		Kv result = Kv.create();
		if(is != null) {
			List<Map<Integer, String>> dataList = new ArrayList<Map<Integer, String>>();
			CubeExcelAnalysisEventListener analysisEventListener = new CubeExcelAnalysisEventListener(CubeConstants.DEFAULT_READ_EXCEL_SIZE, false, dataList::addAll);
			try {
				// 读取部分数据
				ExcelReader excelReader = EasyExcel.read(is, analysisEventListener).excelType(ExcelTypeEnum.valueOf(extension.toUpperCase())).build();
				if(StrUtil.isBlank(config.getSheetName())) {
					List<ReadSheet> sheets = excelReader.excelExecutor().sheetList();
					result.set("sheets", sheets);
				}
				excelReader.read(new ReadSheet(null, StrUtil.isNotBlank(config.getSheetName()) ? config.getSheetName() : null));
				excelReader.finish();
			} catch (Exception e) {
				if (e.getCause() instanceof ExcelReadLimitException || e instanceof ExcelReadLimitException) {
				} else {
					log.error(e.getMessage(), e);
				}
			} finally {
				IoUtil.close(is);
			}
			// 表头数据
			Map<Integer, String> headDataMap = analysisEventListener.getHeadMap();
			List<FileStructure> fileStructList = new ArrayList<FileStructure>();
			// 表头和数据集不为空
			if (headDataMap != null && !headDataMap.isEmpty() && !dataList.isEmpty()) {
				headDataMap.forEach((k, v) -> {
					FileStructure fileStructure = new FileStructure();
					fileStructure.setColumnName(CubeConstants.COLUMN_NAME_PREFIX + k);
					fileStructure.setColumnType(CubeUtils.resolveDataType(k, dataList));
					fileStructure.setComment(v);
					fileStructure.setColumnIndex(k);
					fileStructList.add(fileStructure);
				});
			}
			result.set("fields", fileStructList);
			return R.data(result);
		}
		return R.fail("读取文件结构失败，请检查文件是否存在");
	}
}
