/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.resource.endpoint;

import com.alibaba.fastjson.JSONObject;
import com.google.gson.GsonBuilder;
import io.swagger.annotations.Api;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.controller.CommonRequestController;
import org.springblade.common.controller.vo.RequestVO;
import org.springblade.common.utils.AESUtil;
import org.springblade.common.utils.HttpClientUtil;
import org.springblade.core.launch.constant.AppConstant;
import org.springblade.core.oss.model.BladeFile;
import org.springblade.core.oss.model.OssFile;
import org.springblade.core.secure.annotation.PreAuth;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tenant.annotation.NonDS;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.constant.RoleConstant;
import org.springblade.core.tool.utils.FileUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.resource.builder.oss.OssBuilder;
import org.springblade.modules.resource.entity.Attach;
import org.springblade.modules.resource.entity.BusEntity;
import org.springblade.modules.resource.service.IAttachService;
import org.springblade.modules.system.entity.Dept;
import org.springblade.modules.system.service.IDeptService;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;

/**
 * 对象存储端点
 *
 * @author Chill
 */
@NonDS
@RestController
@AllArgsConstructor
@Api(value = "对象存储端点", tags = "对象存储端点")
@Slf4j
@RequestMapping(AppConstant.APPLICATION_RESOURCE_NAME + "/oss/endpoint")
public class OssEndpoint {

	/**
	 * 对象存储构建类
	 */
	private final OssBuilder ossBuilder;

	/**
	 * 附件表服务
	 */
	private final IAttachService attachService;

	private IDeptService deptService;

	/**
	 * 创建存储桶
	 *
	 * @param bucketName 存储桶名称
	 * @return Bucket
	 */
	@SneakyThrows
	@PostMapping("/make-bucket")
	@PreAuth(RoleConstant.HAS_ROLE_ADMIN)
	public R makeBucket(@RequestParam String bucketName) {
		ossBuilder.template().makeBucket(bucketName);
		return R.success("创建成功");
	}

	/**
	 * 创建存储桶
	 *
	 * @param bucketName 存储桶名称
	 * @return R
	 */
	@SneakyThrows
	@PostMapping("/remove-bucket")
	@PreAuth(RoleConstant.HAS_ROLE_ADMIN)
	public R removeBucket(@RequestParam String bucketName) {
		ossBuilder.template().removeBucket(bucketName);
		return R.success("删除成功");
	}

	/**
	 * 拷贝文件
	 *
	 * @param fileName       存储桶对象名称
	 * @param destBucketName 目标存储桶名称
	 * @param destFileName   目标存储桶对象名称
	 * @return R
	 */
	@SneakyThrows
	@PostMapping("/copy-file")
	public R copyFile(@RequestParam String fileName, @RequestParam String destBucketName, String destFileName) {
		ossBuilder.template().copyFile(fileName, destBucketName, destFileName);
		return R.success("操作成功");
	}

	/**
	 * 获取文件信息
	 *
	 * @param fileName 存储桶对象名称
	 * @return InputStream
	 */
	@SneakyThrows
	@GetMapping("/stat-file")
	public R<OssFile> statFile(@RequestParam String fileName) {
		return R.data(ossBuilder.template().statFile(fileName));
	}

	/**
	 * 获取文件相对路径
	 *
	 * @param fileName 存储桶对象名称
	 * @return String
	 */
	@SneakyThrows
	@GetMapping("/file-path")
	public R<String> filePath(@RequestParam String fileName) {
		return R.data(ossBuilder.template().filePath(fileName));
	}


	/**
	 * 获取文件外链
	 *
	 * @param fileName 存储桶对象名称
	 * @return String
	 */
	@SneakyThrows
	@GetMapping("/file-link")
	public R<String> fileLink(@RequestParam String fileName) {
		return R.data(ossBuilder.template().fileLink(fileName));
	}

	/**
	 * 上传文件
	 *
	 * @param file 文件
	 * @return ObjectStat
	 */
	@SneakyThrows
	@PostMapping("/put-file-web")
	public R putFileWeb(@RequestParam MultipartFile file) {
		BladeFile bladeFile = ossBuilder.template().putFile(file.getOriginalFilename(), file.getInputStream());
		return R.data(bladeFile);
	}

	/**
	 * 上传文件
	 *
	 * @param file 文件
	 * @return ObjectStat
	 */
	@SneakyThrows
	@PostMapping("/put-file-app")
	public String putFileApp(@RequestParam MultipartFile file) {
		Dept dept = deptService.getById(Long.valueOf(AuthUtil.getDeptId().split(",")[0]));
		BladeFile bladeFile = ossBuilder.template().putFile(file.getOriginalFilename(), file.getInputStream());
		if (dept.getAncestors().contains("220200000000")) {
			String url = "http://111.26.204.4:6543/blade-resource/oss/endpoint/put-file";
			HttpClientUtil.doPostUploadFile(url, file);
		}
		return AESUtil.encrypt(JSONObject.toJSONString(R.data(bladeFile)), "2SexR1rfjZ8CD3M6");
	}

	/**
	 * 上传文件
	 *
	 * @param file 文件
	 * @return ObjectStat
	 */
	@SneakyThrows
	@PostMapping("/put-file")
	public R<BladeFile> putFile(@RequestParam MultipartFile file) {
		BladeFile bladeFile = ossBuilder.template().putFile(file.getOriginalFilename(), file.getInputStream());
		//将file签名转成base64 传如三类区
		R base64R = qzToBase64(file);
		String fileName = file.getOriginalFilename();
		if(base64R.getCode() == 601){
			log.error(base64R.getMsg());
		}else{
			String base64Qz = "data:image/jpg;base64,";
			//视频文件
			if(fileName.contains(".mp4")){
				base64Qz = "data:video/mp4;base64,";
			}
			//将base64传入三类
			String reqValue =base64Qz + base64R.getData().toString();
			String str = "{\"methodName\":\"putFile3\",\"className\":\"ossEndpoint\",\"params\":{\"fileName\":\""+fileName+"\",\"base64\":\""+reqValue+"\"},\"token\":\"bearer \"}";
			String requestJson = getRequstJson(str);
			RequestVO requestVO = JSONObject.parseObject(requestJson,RequestVO.class);
			CommonRequestController commonRequestController = new CommonRequestController();
			//线上
			commonRequestController.zf(requestVO);
			//本地
//			commonRequestController.zf3(requestVO);
		}
		return R.data(bladeFile);
	}
	/**
	 * 上传三类文件
	 *
	 * @return ObjectStat
	 */
	@SneakyThrows
	@PostMapping("/put-file3")
	public R<BladeFile> putFile3(@RequestParam String base64,String fileName) {
		MultipartFile file = base64ToMultipartFile(base64);
		BladeFile bladeFile = ossBuilder.template().putFile(fileName, file.getInputStream());
		return R.data(bladeFile);
	}

	private static MultipartFile base64ToMultipartFile (String s) {
		MultipartFile image = null;
		StringBuilder base64 = new StringBuilder("");
		if (s != null && !"".equals(s)) {
			base64.append(s);
			String[] baseStrs = base64.toString().split(",");
			BASE64Decoder decoder = new BASE64Decoder();
			byte[] b = new byte[0];
			try {
				b = decoder.decodeBuffer(baseStrs[1]);
			} catch (IOException e) {
				e.printStackTrace();
			}
			for (int j = 0; j < b.length; ++j) {
				if (b[j] < 0) {
					b[j] += 256;
				}
			}
			image = new BASE64DecodedMultipartFile(b, baseStrs[0]);
		}
		return image;
	}




	public static String getRequstJson(String reqValue) {
		String dataObjId = "t_jdrh";
		String method = "query";
		BusEntity entity = new BusEntity();
		entity.setId(UUID.randomUUID().toString());
		entity.setJsonrpc("2.0");
		BusEntity.ParamsBean params = new BusEntity.ParamsBean();
		BusEntity.ParamsBean.DataBean data = new BusEntity.ParamsBean.DataBean();
		if (method.equals("connect")) {
			entity.setMethod("connect");
			data.setAppId("4eeb7eb13f9c4753ad3263de95b71ff1");
			SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmssSSS");
			data.setTimestamp(format.format(new Date()));
			data.setNonce("vMksKOwd");
			data.setSign("");
		} else {
			entity.setMethod("query");

			BusEntity.ParamsBean.DataBean.UserInfoBean userInfo = new BusEntity.ParamsBean.DataBean.UserInfoBean();
			userInfo.setUserId("000000");
			userInfo.setUserName("张三");
			userInfo.setSn("39a22c9d353f4ea8bbf5a8703799f400");
			userInfo.setUserDeptNo("220000000000");
			BusEntity.ParamsBean.DataBean.UserInfoBean.ExtAttrBean extAttr = new BusEntity.ParamsBean.DataBean.UserInfoBean.ExtAttrBean();
			extAttr.setIp("20.25.1.126");
			extAttr.setPort("6543");
			userInfo.setExtAttr(extAttr);

			BusEntity.ParamsBean.DataBean.SourceBean source = new BusEntity.ParamsBean.DataBean.SourceBean();
			source.setSourceId("ef6dea086e9b4aa3b26749661fdd315c");
			BusEntity.ParamsBean.DataBean.PageBean page = new BusEntity.ParamsBean.DataBean.PageBean();
			page.setPageNo(1);
			page.setPageSize(10);
			data.setPage(page);
			data.setOrderBy("");
			data.setFields("data");
			data.setCondition("");


			data.setDataObjId(dataObjId);
			data.setSource(source);
			data.setUserInfo(userInfo);
			data.setSessionId("4eeb7eb13f9c4753ad3263de95b71ff1");
			data.setCondition("data='" + reqValue + "'");
		}

		data.setVersion("20190221");
		params.setData(data);
		params.setSign("1qqqqwwwwwwwwwwwwww");
		entity.setParams(params);
		String json = new GsonBuilder().disableHtmlEscaping().create().toJson(entity).toString();
		return json;
	}


	/**
	 * 上传文件
	 *
	 * @param file 文件
	 * @return ObjectStat
	 */
	@SneakyThrows
	@PostMapping("/qzToBase64")
	public R qzToBase64(@RequestParam MultipartFile file) {
		if(file != null){
			String base64 = "";
			try {
				byte[] bytes = file.getBytes();
				base64 = Base64.getEncoder().encodeToString(bytes);
				return R.data(base64);
			} catch (IOException e) {
				e.printStackTrace();
				return R.fail(601,e.getMessage());
			}
		}
		return R.fail(602,"暂无签字照片传递");
	}


	/**
	 * 上传文件
	 *
	 * @param fileName 存储桶对象名称
	 * @param file     文件
	 * @return ObjectStat
	 */
	@SneakyThrows
	@PostMapping("/put-file-by-name")
	public R<BladeFile> putFile(@RequestParam String fileName, @RequestParam MultipartFile file) {
		BladeFile bladeFile = ossBuilder.template().putFile(fileName, file.getInputStream());
		return R.data(bladeFile);
	}

	/**
	 * 上传文件并保存至附件表
	 *
	 * @param file 文件
	 * @return ObjectStat
	 */
	@SneakyThrows
	@PostMapping("/put-file-attach")
	public R<BladeFile> putFileAttach(@RequestParam MultipartFile file) {
		String fileName = file.getOriginalFilename();
		BladeFile bladeFile = ossBuilder.template().putFile(fileName, file.getInputStream());
		Long attachId = buildAttach(fileName, file.getSize(), bladeFile);
		bladeFile.setAttachId(attachId);
		return R.data(bladeFile);
	}

	/**
	 * 上传文件并保存至附件表
	 *
	 * @param fileName 存储桶对象名称
	 * @param file     文件
	 * @return ObjectStat
	 */
	@SneakyThrows
	@PostMapping("/put-file-attach-by-name")
	public R<BladeFile> putFileAttach(@RequestParam String fileName, @RequestParam MultipartFile file) {
		BladeFile bladeFile = ossBuilder.template().putFile(fileName, file.getInputStream());
		Long attachId = buildAttach(fileName, file.getSize(), bladeFile);
		bladeFile.setAttachId(attachId);
		return R.data(bladeFile);
	}

	/**
	 * 构建附件表
	 *
	 * @param fileName  文件名
	 * @param fileSize  文件大小
	 * @param bladeFile 对象存储文件
	 * @return attachId
	 */
	private Long buildAttach(String fileName, Long fileSize, BladeFile bladeFile) {
		String fileExtension = FileUtil.getFileExtension(fileName);
		Attach attach = new Attach();
		attach.setDomainUrl(bladeFile.getDomain());
		attach.setLink(bladeFile.getLink());
		attach.setName(bladeFile.getName());
		attach.setOriginalName(bladeFile.getOriginalName());
		attach.setAttachSize(fileSize);
		attach.setExtension(fileExtension);
		attachService.save(attach);
		return attach.getId();
	}

	/**
	 * 删除文件
	 *
	 * @param fileName 存储桶对象名称
	 * @return R
	 */
	@SneakyThrows
	@PostMapping("/remove-file")
	@PreAuth(RoleConstant.HAS_ROLE_ADMIN)
	public R removeFile(@RequestParam String fileName) {
		ossBuilder.template().removeFile(fileName);
		return R.success("操作成功");
	}

	/**
	 * 批量删除文件
	 *
	 * @param fileNames 存储桶对象名称集合
	 * @return R
	 */
	@SneakyThrows
	@PostMapping("/remove-files")
	@PreAuth(RoleConstant.HAS_ROLE_ADMIN)
	public R removeFiles(@RequestParam String fileNames) {
		ossBuilder.template().removeFiles(Func.toStrList(fileNames));
		return R.success("操作成功");
	}

}
