package com.tzy.common.utils.qiniu;

import com.alibaba.fastjson.JSONObject;
import com.qiniu.common.QiniuException;
import com.qiniu.common.Zone;
import com.qiniu.http.Client;
import com.qiniu.http.Response;
import com.qiniu.sms.SmsManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.persistent.FileRecorder;
import com.qiniu.util.Auth;
import com.qiniu.util.StringMap;
import com.tzy.common.config.Global;
import com.tzy.common.dto.Result;
import com.tzy.common.utils.bean.JSONTools;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 七牛云存储
 */
@Slf4j
public class QiniuUtil {

	private static final String HUAD = "华东";
	public static String QINIU_TOKEN = "qiniu_token";
	private static final String HUAB = "华北";
	private static final String HUAN = "华南";
	private static final String BEIM = "北美";
	private static final String accessKey = "RYT6zfQA5Yf4IKgbaDBPMjEgQmzKdcfN48M8VIvI";
	private static final String secretKey = "4P9slQYFTQeomzEMRj3Vq8n_WSv3IvbUvTSmwMwa";
	private static final String bucketName = "tzy-admin-public";
	private static final long expires = 3600L;
	private static final String url = "https://static.public.hobbystock.cn";
	private static final String imgUrl = "http://ai.qiniuapi.com/v3/image/censor";
	private static final String textUrl = "http://ai.qiniuapi.com/v3/text/censor";
	private static final String CENSOR_TYPE_TEXT = "text";
	private static final String CENSOR_TYPE_IMG = "img";
	private static final String CENSOR_PASS = "pass";
	private static final String CENSOR_BLOCK = "block";
	private static final String defaultTextType = "ad,politics,terrorism,abuse,porn,contraband";
	private static final long resumableSize = 4 * 1024 * 1024; //4MB

	private Map<String, Object> qiniuConfig = new HashMap<>();
	private static Auth auth = null;
	private static SmsManager smsManager = null;


	static {
		//qiniuConfig.put("accessKey",config.getAccessKey());
		//qiniuConfig.put("secretKey",config.getSecretKey());
		//qiniuConfig.put("bucket",config.getBucket());
		if (auth == null) {
			auth = Auth.create(accessKey, secretKey);
		}
		if (smsManager == null) {
			smsManager = new SmsManager(auth);
		}
	}

   /* public static void main(String[] args) {
        Map<String,Object> qiniuConfig = new HashMap<>();
        qiniuConfig.put("defultSize",150);
        qiniuConfig.put("zone","HUAD");
        qiniuConfig.put("accessKey","RYT6zfQA5Yf4IKgbaDBPMjEgQmzKdcfN48M8VIvI");
        qiniuConfig.put("secretKey","4P9slQYFTQeomzEMRj3Vq8n_WSv3IvbUvTSmwMwa");
        qiniuConfig.put("bucket","tzy-admin-public");
        File file = new File("D:\\Project\\card\\doc\\4.资料\\cover\\login-background.jpg");
        FileItem fileItem = createFileItem(file);
        MultipartFile multipartFile = new CommonsMultipartFile(fileItem);
        QiniuUtil qiniuUtil = QiniuUtil.initConfig(qiniuConfig);
        System.out.println(qiniuUtil.upload(multipartFile,false,""));
//        String p = "D:\\home\\tzy\\uploadpath";
//        List<File> files = getFiles(p);
//        System.out.println(files.size());
//        QiniuUtil qiniuUtil = QiniuUtil.initConfig(qiniuConfig);
//        for(File file : files){
//            String subStr = file.getAbsolutePath().substring(p.length(), file.getAbsolutePath().length());
//            String names = subStr.substring(1, subStr.lastIndexOf("\\")).replaceAll("\\\\", "/")+"/";
//            Result result = qiniuUtil.saveFile(file, false,names);
//            System.out.println(result.toString());
//        }

    }*/

	public static String getUpToken() {
		return auth.uploadToken(bucketName);
	}

	public static String getUpToken(String bucketName) {
		return auth.uploadToken(bucketName);
	}

	public static boolean qiniuCensor(Map<String, Object> data, String type) {
		String reqUrl = "";
		if (CENSOR_TYPE_TEXT.equals(type)) {
			reqUrl = textUrl;
		} else if (CENSOR_TYPE_IMG.equals(type)) {
			reqUrl = imgUrl;
		} else {
			return false;
		}
		Object filterType = data.get("type");
		List<String> filterTypes;
		if (filterType != null) {
			filterTypes = Arrays.asList(filterType.toString().split(","));
		} else {
			filterTypes = Arrays.asList("politics", "terrorism", "abuse", "porn");
		}
		String body = JSONTools.obj2json(data);
		String authStr = auth.signQiniuAuthorization(reqUrl, "POST", body.getBytes(), "application/json");
		StringMap header = new StringMap();
		header.put("Authorization", "Qiniu " + authStr);
		Client client = new Client();
		try {
			Response response = client.post(reqUrl, body.getBytes(), header, Client.JsonMime);
			log.debug("七牛校验返回结果:{}", response.bodyString());
			if (response.isOK()) {
				CensorDTO censorDTO = JSONTools.jsonStr2obj(response.bodyString(), CensorDTO.class);
				String suggestion = censorDTO.getResult().getSuggestion();
				if (CENSOR_BLOCK.equalsIgnoreCase(suggestion)) {
					List<String> unPassTypes = censorDTO.getResult().getScenes().getAntispam().getDetails().stream()
							.map(SceneDetailDTO::getLabel)
							.filter(filterTypes::contains)
							.collect(Collectors.toList());
					return CollectionUtils.isEmpty(unPassTypes);
				} else {
					return true;
				}
			}
		} catch (Exception e) {
			log.error("七牛校验异常:", e);
		}
		return false;
	}

	/**
	 * 校验文字
	 * @param text
	 * @return true:通过
	 */
	public static boolean checkText(String text) {
		// Map<String, Object> param = ImmutableMap.of("data", ImmutableMap.of("text", text),
		// 		"type", defaultTextType);
		Map<String, Object> dataMap = new HashMap<>();
		dataMap.put("text", text);
		Map<String, Object> param = new HashMap<>();
		param.put("data", dataMap);
		param.put("type", defaultTextType);
		return qiniuCensor(param,CENSOR_TYPE_TEXT);

	}

	public static void testSignQiniuAuthorization() {
		Map<String, Object> urlData = new HashMap<>();
		urlData.put("uri", "http://static.public.hobbystocks.cn/FggHQoZ8oV6kIe-QOvM7Hveawcyi");
		Map<String, Object> params = new HashMap<>();
		params.put("scenes", Arrays.asList("pulp", "terror", "behavior").toArray());
		Map<String, Object> data = new HashMap<>();
		data.put("data", urlData);
		data.put("params", params);
		String body = JSONTools.obj2json(data);
		String authStr = auth.signQiniuAuthorization("http://ai.qiniuapi.com/v3/image/censor", "POST", body.getBytes(), "application/json");
		StringMap header = new StringMap();
		header.put("Authorization", "Qiniu " + authStr);
		Client client = new Client();
		Response response = null;
		try {
			response = client.post("http://ai.qiniuapi.com/v3/image/censor", body.getBytes(), header, Client.JsonMime);
			//System.out.println(response.bodyString());
			CensorDTO censorDTO = JSONTools.jsonStr2obj(response.bodyString(), CensorDTO.class);
			Object suggestion = censorDTO.getResult().getSuggestion();
			log.debug("七牛校验返回结果2:{}", suggestion);
		} catch (QiniuException e) {
			//e.printStackTrace();
		}

		//return auth.signQiniuAuthorization("http://ai.qiniuapi.com/v3/image/censor","POST",body.getBytes(),"application/json");
	}

	public static List<File> getFiles(String path) {
		File root = new File(path);
		List<File> files = new ArrayList<File>();
		if (!root.isDirectory()) {
			files.add(root);
		} else {
			File[] subFiles = root.listFiles();
			for (File f : subFiles) {
				files.addAll(getFiles(f.getAbsolutePath()));
			}
		}
		return files;
	}

	/**
	 * 注册 配置
	 *
	 * @param qiniuConfig
	 * @return
	 */
	public static QiniuUtil initConfig(Map<String, Object> qiniuConfig) {
		QiniuUtil qiniuUtil = new QiniuUtil();
		qiniuUtil.qiniuConfig = qiniuConfig;
		return qiniuUtil;
	}

	/**
	 * @return
	 */
	public Result saveFile(File file, boolean isRename, String newName, String path) {
		Result result = new Result();
		try {
			FileItem fileItem = createFileItem(file);
			MultipartFile multipartFile = new CommonsMultipartFile(fileItem);
			//判断文件大于4Mb 使用 分片上传
			if (resumableSize < file.length())
				return uploadResumable(multipartFile, true, newName, path);//文件大于4MB 使用分片上传
			result = upload(multipartFile, isRename, newName, path);
		} catch (Exception e) {
			e.printStackTrace();
			result.error(-1, file.getName());
		}
		log.info(" 七牛云上传文件：{} ", result);
		return result;
	}

	/**
	 * 文件上传
	 *
	 * @param request
	 * @param isRename
	 * @param code
	 */
	public Result saveFile(HttpServletRequest request, boolean isRename, String newName, String code) {
		try {
			MultipartResolver resolver = new CommonsMultipartResolver(request.getSession().getServletContext());
			MultipartHttpServletRequest multipart = resolver.resolveMultipart(request);
			List<MultipartFile> files = multipart.getFiles("files");//服務器獲取上傳文件的方式
			if ((files == null || files.size() == 0) && request instanceof MultipartHttpServletRequest) {
				//本地tomcat 獲取文件上傳的方式
				MultipartHttpServletRequest multipartDev = (MultipartHttpServletRequest) request;
				files = multipartDev.getFiles("files");
			}
			if (null == files || files.size() <= 0) {
				log.info("files>>>" + files);
				return Result.error(-1, "文件为空");
			}
			//保存文件到本地
			List<Map> filepaths = uploads(files, isRename, newName, code);
			if (null == filepaths || filepaths.size() == 0) return Result.error(-1, "文件为空");
			//處理文件保存的路徑
			List<String> virtualpaths = filepaths.stream().map(map -> {
				Map<String, Object> fileInfo = (Map<String, Object>) map.get("fileInfo");
				return (null != fileInfo && !fileInfo.isEmpty() ? "/" + fileInfo.get("virtualpath") : "");
			}).collect(Collectors.toList());
			if (null == virtualpaths || virtualpaths.size() == 0) return Result.error(-1, "文件上传失败");
			//打印取得的文件路徑
			virtualpaths.stream().forEach(System.out::println);
			String join = StringUtils.join(virtualpaths, ",");
			return Result.ok()
					.put("virtualpath", join)
					;
		} catch (Exception e) {
			e.printStackTrace();
			return Result.error(-2, e.getMessage());
		}
	}

	/**
	 * 多文件上傳
	 *
	 * @param files
	 * @param isRename
	 * @param names
	 * @return
	 */
	public List<Map> uploads(List<MultipartFile> files, boolean isRename, String newName, String... names) throws Exception {
		List<Map> maps = new ArrayList<>();
		if (null != files && files.size() > 0) {
			for (MultipartFile file : files) {
				Result result = new Result();
				//判断文件大于4Mb 使用 分片上传
				if (resumableSize < file.getSize()) {
					result = uploadResumable(file, true, newName, names);//文件大于4MB 使用分片上传
				} else {
					result = upload(file, isRename, newName, names);
				}
				if (result.isSuccess()) maps.add(result.getData());
//                else throw new Exception(result.getMsg());
			}
		}
		return maps;
	}

	/**
	 * 单文件上传
	 *
	 * @param file
	 * @param isRename
	 * @param names
	 */
	public Result upload(MultipartFile file, boolean isRename, String newName, String... names) {
		if (null == qiniuConfig || qiniuConfig.isEmpty()) return Result.error(-1, "请设置七牛云配置");
		try {
			Integer defultSize = (Integer) qiniuConfig.get("defultSize");
			checkSize(defultSize, file.getSize());//验证文件大小
			//判断文件大于4Mb 使用 分片上传
			if (resumableSize < file.getSize()) return uploadResumable(file, true, newName, names);//文件大于4MB 使用分片上传
			// 构造一个带指定Zone对象的配置类
			Configuration cfg = new Configuration(Zone.autoZone());
			UploadManager uploadManager = new UploadManager(cfg);
			Auth auth = Auth.create((String) qiniuConfig.get("accessKey"), (String) qiniuConfig.get("secretKey"));
			String upToken = auth.uploadToken((String) qiniuConfig.get("bucket"));
			String key = file.getOriginalFilename();
			log.info("names>>>>>" + StringUtils.join(names, "/"));
			key = ((null != names && names.length > 0) ? StringUtils.join(names, "/") + "/" : "") + getKey(key, isRename, newName);
			log.info("key>>>>" + key);
			Response response = uploadManager.put(file.getBytes(), key, upToken);
			if (null == response || StringUtils.isEmpty(response.bodyString())) {
				return Result.error(-1, "文件未上传成功");
			}
			//解析上传成功的结果
			JSONObject jsonObject = JSONObject.parseObject(response.bodyString());
			if (null == jsonObject || jsonObject.isEmpty()) {
				return Result.error(-1, "文件未上传成功");
			}
			jsonObject.put("virtualpath", "/" + jsonObject.getString("key"));//虚拟地址|可访问地址
			jsonObject.put("absolutePath", qiniuConfig.get("bucket") + "/" + key);//物理地址
			jsonObject.put("fileName", getFileNameNoEx(key) + "." + getExtensionName(key));
			jsonObject.put("size", file.getSize());
			jsonObject.put("fileType", getExtensionName(key));
			response.close();
			return Result.ok()
					.put("fileInfo", jsonObject)
					;
		} catch (Exception e) {
			return Result.error(-1, e.getMessage());
		}
	}

	private static void checkSize(long maxSize, long size) throws Exception {
		// 1M
		int len = 1024 * 1024;
		if (size > (maxSize * len)) {
			throw new Exception("文件超出规定大小");
		}
	}

	/**
	 * 默认不指定key的情况下，以文件内容的hash值作为文件名
	 *
	 * @param file 文件名
	 * @return String
	 */
	private static String getKey(String file, boolean isRename, String newName) {
		long ltime = System.currentTimeMillis();
		return
				(isRename ? (StringUtils.isEmpty(newName) ? ltime : newName) : getFileNameNoEx(file)) +
						"." +
						getExtensionName(file);
	}

	/**
	 * Java文件操作 获取不带扩展名的文件名
	 */
	private static String getFileNameNoEx(String filename) {
		if ((filename != null) && (filename.length() > 0)) {
			int dot = filename.lastIndexOf('.');
			if ((dot > -1) && (dot < (filename.length()))) {
				return filename.substring(0, dot);
			}
		}
		return filename;
	}

	/**
	 * 获取文件扩展名，不带 .
	 */
	private static String getExtensionName(String filename) {
		if ((filename != null) && (filename.length() > 0)) {
			int dot = filename.lastIndexOf('.');
			if ((dot > -1) && (dot < (filename.length() - 1))) {
				return filename.substring(dot + 1);
			}
		}
		return filename;
	}

	private static FileItem createFileItem(File file) {
		FileItemFactory factory = new DiskFileItemFactory(16, null);
		FileItem item = factory.createItem("textField", "text/plain", true, file.getName());
		int bytesRead = 0;
		byte[] buffer = new byte[8192];
		try {
			FileInputStream fis = new FileInputStream(file);
			OutputStream os = item.getOutputStream();
			while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {
				os.write(buffer, 0, bytesRead);
			}
			os.close();
			fis.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return item;
	}

	/**
	 * 分片上传
	 */
	public Result uploadResumable(MultipartFile file, boolean isRename, String newName, String... names) {
		if (null == qiniuConfig || qiniuConfig.isEmpty()) return Result.error(-1, "请设置七牛云配置");
		//构造一个带指定 Region 对象的配置类
		Configuration cfg = new Configuration(Region.region0());
		cfg.resumableUploadAPIVersion = Configuration.ResumableUploadAPIVersion.V2;// 指定分片上传版本
		int TaskCount = Math.toIntExact((file.getSize() / 1024 / 1024 / 4) + 1);
		cfg.resumableUploadMaxConcurrentTaskCount = TaskCount > 5 ? 5 : TaskCount;  // 设置分片上传并发，1：采用同步上传；大于1：采用并发上传
//        cfg.putThreshold = 1*1024*1024;//设置1MB上传
		//  默认不指定key的情况下，以文件内容的hash值作为文件名
		String key = file.getOriginalFilename();
		log.info("names>>>>>" + StringUtils.join(names, "/"));
		key = ((null != names && names.length > 0) ? StringUtils.join(names, "/") + "/" : "") + getKey(key, isRename, newName);
		Auth auth = Auth.create((String) qiniuConfig.get("accessKey"), (String) qiniuConfig.get("secretKey"));
		String upToken = auth.uploadToken((String) qiniuConfig.get("bucket"));
		String tmpdirPath = Global.getUploadPath() + "/resumable/";
		String localTempDir = Paths.get(tmpdirPath, (String) qiniuConfig.get("bucket")).toString();
		try {
			//设置断点续传文件进度保存目录
			FileRecorder fileRecorder = new FileRecorder(localTempDir);
			UploadManager uploadManager = new UploadManager(cfg, fileRecorder);
			try {
				Response response = uploadManager.put(file.getBytes(), key, upToken);
				//解析上传成功的结果
				JSONObject jsonObject = JSONObject.parseObject(response.bodyString());
				if (null == jsonObject || jsonObject.isEmpty()) {
					return Result.error(-1, "文件未上传成功");
				}
				jsonObject.put("virtualpath", "/" + jsonObject.getString("key"));//虚拟地址|可访问地址
				jsonObject.put("absolutePath", qiniuConfig.get("bucket") + "/" + key);//物理地址
				jsonObject.put("fileName", getFileNameNoEx(key) + "." + getExtensionName(key));
				jsonObject.put("size", file.getSize());
				jsonObject.put("fileType", getExtensionName(key));
				response.close();
				return Result.ok()
						.put("fileInfo", jsonObject)
						;
			} catch (QiniuException ex) {
				return Result.error(-1, ex.getMessage());
			}
		} catch (IOException ex) {
			ex.printStackTrace();
			return Result.error(-1, ex.getMessage());
		}
	}


}
