package com.cusc.nirvana.user.rnr.fp.controller;


import com.alibaba.excel.util.FileUtils;
import com.cusc.nirvana.common.result.Response;
import com.cusc.nirvana.user.exception.CuscUserException;
import com.cusc.nirvana.user.rnr.fp.dto.FileDownloadDTO;
import com.cusc.nirvana.user.rnr.fp.dto.FileRecordDTO;
import com.cusc.nirvana.user.rnr.fp.dto.FileUploadDTO;
import com.cusc.nirvana.user.rnr.fp.dto.ImageBase64DTO;
import com.cusc.nirvana.user.rnr.fp.service.IFileService;
import com.cusc.nirvana.user.util.CuscStringUtils;
import com.cusc.nirvana.user.util.crypt.DataCryptService;
import com.cusc.nirvana.user.util.crypt.Sm4Util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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 javax.annotation.Resource;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.*;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;


/**
 * @author stayand
 */
@RestController
@RequestMapping("/file")
@Slf4j
public class FileSystemController {

	@Resource
	private IFileService fileService;

	@Value("${rnr.image.watermark.source:/data/imageTemp/source/}")
	private String sourceBasePath;
	@Value("${rnr.image.watermark.water:/data/imageTemp/water/}")
	private String waterBasePath;
	@Value("${rnr.image.watermark.target:/data/imageTemp/target/}")
	private String targetBasePath;

	@Autowired
	private DataCryptService dataCryptService;

	@Resource
	private ExecutorService textWaterMarkThreadPool4RemoveTemp;

	@Value("${T1.picturePower}")
	private boolean picturePower;

    /**
     * 获取文件大小
     * @param
     */
    @PostMapping("/getFileSize")
    public Response<FileRecordDTO> getFileSize(@RequestBody FileRecordDTO bean) {
        if (bean == null || StringUtils.isBlank(bean.getUuid())) {
           return Response.createError("参数uuid为空");
        }

		Double fileSize = fileService.getFileSize(bean.getUuid());
		FileRecordDTO fileRecordDTO = new FileRecordDTO();
		fileRecordDTO.setFileSize(fileSize);
		return Response.createSuccess(fileRecordDTO);

    }

    @PostMapping("/getBase64")
    public Response<ImageBase64DTO> getBase64(@RequestBody FileDownloadDTO fileDownloadDTO) {
        if (fileDownloadDTO == null || StringUtils.isBlank(fileDownloadDTO.getUuid())) {
            return Response.createError("参数uuid为空");
        }

		String base64 = fileService.downLoadBase64(fileDownloadDTO.getUuid());
		ImageBase64DTO base64DTO = new ImageBase64DTO();
		base64DTO.setBase64(base64);

		return Response.createSuccess(base64DTO);
    }

    @PostMapping("/uploadImage")
    public Response<FileRecordDTO> uploadImage(FileUploadDTO fileUploadDTO) {
        try {
			//文件大小必须大于0
			if (fileUploadDTO.getFile().getSize() < 1) {
				return Response.createError("文件内容不能为空");
			}
			String originalFilename = fileUploadDTO.getFile().getOriginalFilename();
			if(CuscStringUtils.isEmpty(originalFilename)){
				return Response.createError("文件名不能为空");
			}
//			InputStream inputStream = fileUploadDTO.getFile().getInputStream();
			String suffix = "png";
			if (StringUtils.isNotBlank(originalFilename)) {
				suffix = originalFilename.substring(originalFilename.lastIndexOf(".")+1);
			}
			//加水印
			String fileName = fileService.doMarkText(fileUploadDTO.getFile(),fileUploadDTO.getUserId());

			byte[] image4Encrypt = doEncryptImage(fileName);//加密

			ByteArrayInputStream resource = null;
			File file = new File(targetBasePath + fileName);
			resource = new ByteArrayInputStream(image4Encrypt);
			String fileKey = fileService.upLoadImage(picturePower?resource:new FileInputStream(file), suffix);
			FileRecordDTO fileRecordDTO = new FileRecordDTO();
			fileRecordDTO.setUuid(fileKey);
			fileRecordDTO.setAccessUrl(fileService.getFileUrl(fileKey));
			fileRecordDTO.setFileName(originalFilename);
			//      删除临时文件
			String finalWaterMarkFileName = fileName;
			boolean res4RemoveTemp = false;
			try {
				res4RemoveTemp = textWaterMarkThreadPool4RemoveTemp.submit(() -> this.removeTemp(finalWaterMarkFileName)).get();
			} catch (InterruptedException e) {
				log.error("removeTemp error:", e.getMessage(), e);
				return Response.createError(e.getMessage());
			} catch (ExecutionException e) {
				log.error("removeTemp error:", e.getMessage(), e);
				return Response.createError(e.getMessage());
			}
			if (!res4RemoveTemp) {
				throw new CuscUserException("500", "删除临时文件异常");
			}
			return Response.createSuccess(fileRecordDTO);
        }catch (Exception e){
            log.error("uploadImage error, e : {}",e);
            return Response.createError("上传失败");
        }
    }
	private boolean removeTemp(String fileName) {
		String sourceFilePath = sourceBasePath + fileName;
		String waterFilePath = waterBasePath + fileName;
		String targetFilePath = targetBasePath + fileName;
		FileUtils.delete(new File(sourceFilePath));
		log.info("removeTemp filepath = {}", sourceFilePath);
		FileUtils.delete(new File(waterFilePath));
		log.info("removeTemp filepath = {}", waterFilePath);
		FileUtils.delete(new File(targetFilePath));
		log.info("removeTemp filepath = {}", targetFilePath);
		return true;
	}

	@PostMapping("/uploadFile")
	public Response<FileRecordDTO> uploadFile(FileUploadDTO fileUploadDTO) {
		try {
			//文件大小必须大于0
			if (fileUploadDTO.getFile().getSize() < 1) {
				return Response.createError("文件内容不能为空");
			}
			String originalFilename = fileUploadDTO.getFile().getOriginalFilename();
			if(CuscStringUtils.isEmpty(originalFilename)){
				return Response.createError("文件名不能为空");
			}
			InputStream inputStream = fileUploadDTO.getFile().getInputStream();
			String suffix = "";
			if (StringUtils.isNotBlank(originalFilename)) {
				suffix = originalFilename.substring(originalFilename.lastIndexOf(".")+1);
			}
			String fileKey = fileService.upLoadFile(inputStream, suffix);
			FileRecordDTO fileRecordDTO = new FileRecordDTO();
			fileRecordDTO.setUuid(fileKey);
			fileRecordDTO.setAccessUrl(fileService.getFileUrl(fileKey));
			fileRecordDTO.setFileName(originalFilename);

			return Response.createSuccess(fileRecordDTO);
		}catch (Exception e){
			log.error("uploadImage error, e : {}",e);
			return Response.createError("上传失败");
		}
	}


	@PostMapping("/getUrl")
	public Response<FileRecordDTO> getUrl(@RequestBody FileDownloadDTO fileDownloadDTO){
		String fileUrl = fileService.getFileUrl(fileDownloadDTO.getUuid());

		FileRecordDTO fileRecordDTO = new FileRecordDTO();
		fileRecordDTO.setAccessUrl(fileUrl);
		fileRecordDTO.setUuid(fileDownloadDTO.getUuid());

		return Response.createSuccess(fileRecordDTO);
	}

	//加密
	private byte[] doEncryptImage(String image4Watermark) throws NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, NoSuchProviderException, InvalidKeyException {
		File f = new File(targetBasePath + image4Watermark);
		byte[] data = file2byte(f);
		byte[] encryptFileBytes = Sm4Util.encryptEcbPaddingByte(dataCryptService.getSm4Key().getBytes(), data);
		return encryptFileBytes;
	}

	private byte[] file2byte(File filePath) {
		byte[] buffer = null;
		try {
			FileInputStream fis = new FileInputStream(filePath);
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			byte[] b = new byte[1024];
			int n;
			while ((n = fis.read(b)) != -1) {
				bos.write(b, 0, n);
			}
			fis.close();
			bos.close();
			buffer = bos.toByteArray();
		} catch (FileNotFoundException e) {
			log.error("file2byte error", e.getMessage());
		} catch (IOException e) {
			log.error("file2byte error", e.getMessage());
		}
		return buffer;
	}

}
