package cn.myapps.runtime.dynaform.form.controller;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.ftp.Ftp;
import cn.hutool.extra.ftp.FtpMode;
import cn.myapps.common.controller.Resource;
import cn.myapps.common.controller.ResourceNotFoundException;
import cn.myapps.common.data.ParamsTable;
import cn.myapps.common.exception.OBPMValidateException;
import cn.myapps.common.util.FileWriteUtil;
import cn.myapps.common.util.PropertyUtil;
import cn.myapps.common.util.StringUtil;
import cn.myapps.conf.FileModeConfig;
import cn.myapps.designtime.common.service.DesignTimeServiceManager;
import cn.myapps.designtime.form.service.FormDesignTimeService;
import cn.myapps.runtime.common.controller.AbstractRuntimeController;
import cn.myapps.runtime.common.service.RunTimeServiceManager;
import cn.myapps.runtime.dynaform.document.ejb.Document;
import cn.myapps.runtime.dynaform.document.ejb.DocumentProcess;
import cn.myapps.runtime.dynaform.form.ejb.Form;
import cn.myapps.runtime.dynaform.upload.ejb.UploadInfo;
import cn.myapps.runtime.dynaform.upload.ejb.UploadProcess;
import cn.myapps.runtime.dynaform.upload.ejb.UploadVO;
import cn.myapps.util.ftp.FtpUtils;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.Option;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.UUID;

import static com.jayway.jsonpath.JsonPath.parse;

/**
 * FileUpload RESTful 接口
 * @a
 * uthor spy
 */
@Api(tags = "表单文件上传执行模块")
@RequestMapping(value = "/api")
@RestController
public class FileUploadController extends AbstractRuntimeController {


	/**
	 * 通过文件路劲获取对应的pdf文件
	 * @param fileId 文件id
	 * @param path 路径
	 * @return
	 * @throws Exception
	 */
	@GetMapping("/runtime/file/{fileId}/pdf")
	@ResponseStatus(HttpStatus.OK)
	@ApiOperation(value = "通过文件路劲获取对应的pdf文件", notes = "通过文件路劲获取对应的pdf文件")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "fileId",value = "文件id",required = true,paramType = "path",dataType = "string"),
			@ApiImplicitParam(name = "path",value = "路径",required = true,paramType = "query",dataType = "string")
	})
	public Resource getPdfFile(@PathVariable String fileId , @RequestParam("path") String path)throws Exception {
		if(StringUtil.isBlank(path)){
			return resourceNotFound(new ResourceNotFoundException("路径为空"));
		}
		String tmp = path;
		int index = tmp.indexOf(fileId);

		StringBuffer pdfPath = new StringBuffer();
		pdfPath.append(tmp.substring(0,index));
		pdfPath.append("swf");
		pdfPath.append("/").append(fileId).append(".pdf");

		String rootPath = PropertyUtil.getPath();
		String filePath =rootPath+pdfPath.toString();
		File file = new File(filePath);

		if(!file.exists()){
			//文件是pdf文件直接返回源文件
			if(path.lastIndexOf(".pdf")>0){
				return success("ok",path);
			}
			return resourceNotFound(new ResourceNotFoundException("PDF资源未找到"));
		}
		return success("ok",pdfPath);
	}

	/**
	 * 文件上传
	 *
	 * @param applicationId  软件id
	 * @param allowedTypes   允许上传类型
	 * @param fieldId        表单字段
	 * @param fileSaveMode   文件保存模式
	 * @param path           上传文件保存的路劲
	 * @param actionType     类型
	 * @param multipartFiles 多个文件
	 * @return
	 * @throws Exception
	 */
	@PostMapping("/runtime/upload")
	@ResponseStatus(HttpStatus.OK)
	@ApiOperation(value = "文件上传", notes = "文件上传")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "query", dataType = "string"),
			@ApiImplicitParam(name = "allowedTypes", value = "允许上传类型", required = true, paramType = "query", dataType = "string"),
			@ApiImplicitParam(name = "fieldId", value = "表单字段", required = true, paramType = "query", dataType = "string"),
			@ApiImplicitParam(name = "fileSaveMode", value = "文件保存模式", required = true, paramType = "query", dataType = "string"),
			@ApiImplicitParam(name = "path", value = "上传文件保存的路径", required = true, paramType = "query", dataType = "string"),
			@ApiImplicitParam(name = "actionType", value = "类型", required = true, paramType = "query", dataType = "string"),
			@ApiImplicitParam(name = "multipartFiles", value = "多个文件", required = true, paramType = "query", dataType = "string")
	})
	public Resource upload(@RequestParam("applicationId") String applicationId,
						   @RequestParam("allowedTypes") String allowedTypes, @RequestParam("fieldId") String fieldId,
						   @RequestParam("fileSaveMode") String fileSaveMode, @RequestParam("path") String path,
						   @RequestParam("actionType") String actionType, @RequestParam("files") MultipartFile[] multipartFiles)
			throws Exception {

		JSONArray result = new JSONArray();
		if (multipartFiles.length > 0) {
			for (int i = 0; i < multipartFiles.length; i++) {
				// 获取上传文件
				MultipartFile multipartFile = multipartFiles[i];
				// 生成唯一id
				String id = UUID.randomUUID().toString();
				// 获取上传文件名
				String fileName = multipartFile.getOriginalFilename();
				// 获取上传文件大小
				Long size = multipartFile.getSize();
				// 获取上传文件拓展名
				String extName = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();

				fileName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + extName;

				String uploadContentType = allowedTypes + "/" + extName;

				if (path.indexOf("/") != -1) {
					path = path.substring(1);
				}

				// 获得文件保存的真实路径
//				String savePath = request.getServletContext().getRealPath("");
				String savePath = PropertyUtil.getPath();
				savePath += getUploadInfo(allowedTypes, uploadContentType, fileName, fileSaveMode, path).getFileDir();

				// 加上以当前年份命名的文件夹
				Calendar cal = Calendar.getInstance();
				int year = cal.get(Calendar.YEAR);
				savePath += File.separator + year;

				UploadInfo upload = getUploadInfo(allowedTypes, uploadContentType, fileName, fileSaveMode, path);

				if (fileName.indexOf("/") >= 0 || fileName.indexOf("\\") >= 0) {// 防止非法上传文件到任意目录
					throw new OBPMValidateException("上传的文件名称不合法！");
				}
				if (isNotLegalFileExt(extName)) {
					return error(4001, "上传的文件类型不合法！", null);
				}

				if (FileModeConfig.getUseFtp() && savePath.indexOf("/uploads/lib/icon/") < 0) {
					String uploadPath = upload.getFileDir() + year + "/";// + id + "." + extName;

					//---------------------------------
					Ftp ftp = new Ftp(FileModeConfig.getHost(),
							FileModeConfig.getPort(),
							FileModeConfig.getUserName(),
							FileModeConfig.getPassword()
					);
					ftp.setMode(FtpMode.Passive);

					String destPath = (StrUtil.isEmpty(FileModeConfig.getFilePath()) ? "" : FileModeConfig.getFilePath()) + uploadPath;
					boolean uploadResult = ftp.upload(destPath, id + "." + extName, multipartFile.getInputStream());

					System.out.println(StrUtil.format("路径: {},{}", destPath, fileName));

					IoUtil.close(ftp);
					//---------------------------------

					if (!uploadResult) {
						return error(new Exception("上传失败"));
					}
				} else {
					// 文件夹不存在就创建
					File dir = new File(savePath);
					if (!dir.exists()) {
						dir.mkdirs();
					}

					// 生成文件
					File f = new File(savePath + "/" + id + "." + extName);
					f.createNewFile();
					multipartFile.transferTo(f);

					if (applicationId != null && !applicationId.equals("")) {
						UploadProcess uploadProcess = RunTimeServiceManager.uploadProcess(applicationId);
						UploadVO uploadVO = new UploadVO();
						uploadVO.setId(id);
						uploadVO.setName(upload.getFileName());
						uploadVO.setFieldid(fieldId);
						uploadVO.setType("." + extName);
						uploadVO.setSize(size);
						uploadVO.setModifyDate(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
						uploadVO.setUserid(getUser().getId());
						uploadVO.setPath(upload.getFileDir() + year + "/" + id + "." + extName);
						uploadVO.setFolderPath(upload.getFileDir());
						uploadProcess.doCreate(uploadVO);

						if (!"excelImport".equals(actionType) && isTransferToPdf(uploadVO.getType())) {// excel导入时，不执行swf转换
							//生成文件任务
							String rootPath = PropertyUtil.getPath();
							FileWriteUtil.writeKmConvertTask(rootPath, id, f.getPath());
						}
					}
				}
				JSONObject responseInfoItem = new JSONObject();
				responseInfoItem.put("fileName", upload.getFileSaveName());
				responseInfoItem.put("filePath", upload.getFileDir() + year + "/" + id + "." + extName);
				responseInfoItem.put("fileSize", size);
				responseInfoItem.put("fileType", "." + extName);
				result.add(responseInfoItem);
			}
		}
		return success("ok", result);
	}

	/**
	 * 文件上传
	 * @return
	 * @throws Exception
	 */
	@PostMapping("/runtime/upload/ftp")
	@ResponseStatus(HttpStatus.OK)
	@ApiOperation(value = "文件上传", notes = "文件上传")
	public Resource upload(MultipartFile multipartFile) throws Exception {
		JSONArray result = new JSONArray();
		// 生成唯一id
		String id = UUID.randomUUID().toString();
		// 获取上传文件名
		String fileName = multipartFile.getOriginalFilename();
		// 获取上传文件大小
		Long size = multipartFile.getSize();
		// 获取上传文件拓展名
		String extName = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
		fileName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + extName;

		// 加上以当前年份命名的文件夹
		Calendar cal = Calendar.getInstance();
		int year = cal.get(Calendar.YEAR);

		if (fileName.indexOf("/") >= 0 || fileName.indexOf("\\") >= 0) {// 防止非法上传文件到任意目录
			throw new OBPMValidateException("上传的文件名称不合法！");
		}
		if (isNotLegalFileExt(extName)) {
			return error(4001, "上传的文件类型不合法！", null);
		}

		String uploadPath = "/uploads/item/" + year + "/" + id + "." + extName;
		FtpUtils.bcxUploadFile(FileModeConfig.getHost(),
		FileModeConfig.getUserName(),
		FileModeConfig.getPassword(),
		FileModeConfig.getPort(),
		(StrUtil.isEmpty(FileModeConfig.getFilePath()) ? "": FileModeConfig.getFilePath()) + uploadPath,
		multipartFile.getInputStream());

		JSONObject responseInfoItem = new JSONObject();
		responseInfoItem.put("fileName", fileName);
		responseInfoItem.put("filePath", "/uploads/item/" + year + "/" + id + "." + extName);
		responseInfoItem.put("fileSize", size);
		responseInfoItem.put("fileType", "."+extName);
		result.add(responseInfoItem);
		return success("ok", result);
	}

	public UploadInfo getUploadInfo(String allowedTypes,String uploadContentType,String fileName,String fileSaveMode,String path) {
		// 设置属性
		UploadInfo uploadInfo = new UploadInfo();
		uploadInfo.setAllowedTypes(allowedTypes);
		uploadInfo.setContentType(uploadContentType);
		uploadInfo.setFileName(fileName);
		uploadInfo.setFileSaveMode(fileSaveMode);
		try {
			uploadInfo.setPath(path);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return uploadInfo;
	}

	/**
	 * 是否为不合法文件类型
	 *
	 * @param fileExt
	 * @throws Exception
	 */
	private boolean isNotLegalFileExt(String fileExt) throws Exception {
		String[] excludeTypes = new String[] { "jsp", "class" ,"jspx" };
		if (StringUtil.isBlank(fileExt))
			return true;
//		String fileType = fileExt.substring(1);
		String fileType = fileExt;
		for (int i = 0; i < excludeTypes.length; i++) {
			String excludeType = excludeTypes[i];
			if (StringUtil.isBlank(excludeType))
				continue;
			if (fileType.equalsIgnoreCase(excludeType))
				return true;
		}
		return false;
	}

	/**
	 * 文件排序
	 * @param content 请求包体
	 * @return
	 * @throws Exception
	 */
	@PostMapping("/runtime/files/sort")
	@ResponseStatus(HttpStatus.OK)
	@ApiOperation(value = "文件排序", notes = "文件排序")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "content",value = "请求包体",required = true,paramType = "body",dataType = "string")
	})
	public Resource fileSort(@RequestBody String content) throws Exception{
		Configuration configuration = Configuration.defaultConfiguration();
		configuration = configuration.addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL);

		DocumentContext parse = parse(content, configuration);
		String applicationId = parse.read("$.applicationId");
		String formId = parse.read("$.formId");
		String docId = parse.read("$.docId");
		String itemName = parse.read("$.itemName");
		String itemVal = parse.read("$.itemValue");

		DocumentProcess docProcess = RunTimeServiceManager.documentProcess( applicationId);
		String resultStr = docProcess.updateFileSorting(docId,formId,itemName,itemVal);
		JSONObject jsonObject = JSONObject.fromObject(resultStr);
		JSONArray json = jsonObject.getJSONArray("datas");
		return success("ok", json);
	}

	/**
	 * 删除文件
	 * @param applicationId
	 * 		软件id
	 * @param docId
	 * 		文档id
	 * @param path
	 * 		文件保存路径
	 * @param formId
	 * 		表单id
	 * @return
	 * @throws Exception
	 */
	@DeleteMapping("/runtime/files/delete")
	@ResponseStatus(HttpStatus.OK)
	@ApiOperation(value = "删除文件", notes = "删除文件")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "applicationId",value = "软件id",required = true,paramType = "query",dataType = "string"),
			@ApiImplicitParam(name = "docId",value = "文档id",required = true,paramType = "query",dataType = "string"),
			@ApiImplicitParam(name = "path",value = "文件保存路径",required = true,paramType = "query",dataType = "string"),
			@ApiImplicitParam(name = "formId",value = "表单id",required = true,paramType = "query",dataType = "string")
	})
	public Resource deleteFile(String applicationId,String docId,String path,String formId) throws Exception {
		if (!StringUtil.isBlank(path)) {
			path = URLDecoder.decode(path, "UTF-8");
			UploadProcess uploadProcess = RunTimeServiceManager.uploadProcess(applicationId);
			UploadVO uploadVO = null;
			if (!StringUtil.isBlank(path)
					&& path.indexOf("_/uploads") > 0) {
				String fileId = path.substring(0,
						path.indexOf("_/uploads"));
				uploadVO = (UploadVO) uploadProcess.doView(fileId);
			} else {
				uploadVO = (UploadVO) uploadProcess.findByColumnName1("PATH",
						path);
			}
			if (uploadVO != null) {
				String fileRealPath = request.getServletContext().getRealPath(uploadVO.getPath());
				File file = new File(fileRealPath);
				if (file.exists()) {
					if (!file.delete()) {
						throw new OBPMValidateException("File(" + fileRealPath
								+ ") delete failed");
					}
				}
				uploadProcess.doRemove(uploadVO.getId());

				// 删除上传文件时，更新文档
				if (!StringUtil.isBlank(applicationId)) {
					DocumentProcess docProcess = RunTimeServiceManager.documentProcess(applicationId);
					if (!StringUtil.isBlank(docId)) {
						Document doc = (Document) docProcess.doView(docId);
						if (doc != null) {
							doc = rebuildDocument(doc, getParams(), formId);
							docProcess.doUpdate(doc, false, false);
						}
					}
				}

			}
		}
		return success("ok", "删除成功");
	}

	/**
	 * 重新构建文档
	 *
	 * @param doc
	 * @param params
	 * @return
	 */
	private Document rebuildDocument(Document doc, ParamsTable params, String formid) {
		try {
			if (!StringUtil.isBlank(doc.getId()) && !StringUtil.isBlank(formid)) {
				FormDesignTimeService formPross = DesignTimeServiceManager.formDesignTimeService();
				Form form = (Form) formPross.doView(formid);
				doc = form.createDocument(doc, params, getUser());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return doc;
	}

	/**
	 * 判断文件名是否需要转换pdf
	 * @param name
	 * @return
	 */
	private boolean isTransferToPdf(String name){
		name = name.toLowerCase();
		if(name.indexOf("png") >= 0
				|| name.indexOf("ico") >= 0
				|| name.indexOf(".gif") >= 0
				|| name.indexOf(".jpg") >= 0
				|| name.indexOf(".jpeg") >= 0
				|| name.indexOf(".bmp") >= 0
				|| name.indexOf("pdf") >= 0){
			return false;
		}
		return true;
	}
}
