package cn.timer.api.utils.aliyun;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.event.ProgressEvent;
import com.aliyun.oss.event.ProgressEventType;
import com.aliyun.oss.event.ProgressListener;
import com.aliyun.oss.model.DeleteObjectsRequest;
import com.aliyun.oss.model.DeleteObjectsResult;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.ListObjectsRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.OSSObjectSummary;
import com.aliyun.oss.model.ObjectListing;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.timer.api.utils.Result;
import cn.timer.api.utils.ResultUtil;

/**
 * OSS接口操作示例 1.创建空间 2.上传文件 3.下载文件
 * 
 * @author dsc
 *
 */
@Component
public class OSSUtil {

	@Value("${config-8timer.Aliyun.endpoint}")
	private String endpoint;

	@Value("${config-8timer.Aliyun.ACCESSKEY_ID}")
	private String accessKeyId;

	@Value("${config-8timer.Aliyun.SECRET}")
	private String accessKeySecret;

	@Value("${config-8timer.Aliyun.bucketName}")
	private String bucketName;

	@Value("${config-8timer.Aliyun.bucketName_pri}")
	private String bucketName_pri;

	@Value("${config-8timer.Aliyun.project_package}")
	private String project_package;

	@Value("${config-8timer.Aliyun.expirationTime}")
	private String expirationTime;

	@Value("${config-8timer.Aliyun.expirationTime_pri}")
	private String expirationTime_pri;

	/**
	 * 1.创建储存空间 sout控制台輸出 储存空间名
	 * 
	 * @param bucketName OSS空间名
	 * @return 成功信息
	 */
	public Result<Void> createZone(String bucketName) {
		// Endpoint以杭州为例,其它Region请按实际情况填写。
		// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录
		// https://ram.console.aliyun.com 创建RAM账号。
		// 创建OSSClient实例。

		OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
		// 创建存储空间。
		ossClient.createBucket(bucketName);
		// 关闭OSSClient。
		ossClient.shutdown();
		// 控制台输出空间名
		Logoutput("bucketName:" + bucketName);
		// 返回成功
		return ResultUtil.success("创建OSS空间成功");
	}

	/**
	 * 2.上传文件到8time-v2
	 * 
	 * @param path 上传路径(用'/'分包)
	 * @param ins  输入流
	 * @return
	 */
	public String uploadFile(File path, InputStream ins) {
		// <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
		// String objectName = "8time-v2/test/123.jpg";
		// 创建OSSClient实例。
		Logoutput(endpoint);
		Logoutput(accessKeyId);
		Logoutput(accessKeySecret);
		OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

		// 创建PutObjectRequest对象。
		// 项目名+用户公司id+模块名+文件夹名+文件名
		PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, path.getPath(), ins);
		// [file1,file2,file3],["mk1/img","mk1"]
		// 如果需要上传时设置存储类型与访问权限,请参考以下示例代码。
		// ObjectMetadata metadata = new ObjectMetadata();
		// metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS,
		// StorageClass.Standard.toString());
		// metadata.setObjectAcl(CannedAccessControlList.Private);
		// putObjectRequest.setMetadata(metadata);

		// 上传文件。
		ossClient.putObject(putObjectRequest);

		// 设置URL过期时间为100年。 1s 1h 1d 1y 100y
//		Date expiration = new Date(new Date().getTime() + 1000L * 3600 * 24 * 365 * 100);
		Date now = new Date();
		Date expiration = DateUtil.offset(now, DateField.YEAR, 100); // 一百年之后过期
		// 生成以GET方法访问的签名URL,访客可以直接通过浏览器访问相关内容。
		URL url = ossClient.generatePresignedUrl(bucketName, path.getPath(), expiration);
		Logoutput(String.valueOf(url));

		// 关闭OSSClient。
		ossClient.shutdown();
		// 返回上传成功的文件名
		return url.toString().substring(0,url.toString().lastIndexOf("?"));
	}

	/**
	 * 3.上传文件到8time-v2-private
	 * 
	 * @param path 上传路径(用'/'分包)
	 * @param ins  输入流
	 * @return 文件路径
	 */
	public String uploadPrivateFile(String path, InputStream ins) {
		// <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
		// String objectName = "8time-v2/test/123.jpg";
		// 创建OSSClient实例。
		OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

		// 创建PutObjectRequest对象。
		// 项目名+用户公司id+模块名+文件夹名+文件名
		PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName_pri, path, ins);
		// [file1,file2,file3],["mk1/img","mk1"]
		// 如果需要上传时设置存储类型与访问权限,请参考以下示例代码。
		// ObjectMetadata metadata = new ObjectMetadata();
		// metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS,
		// StorageClass.Standard.toString());
		// metadata.setObjectAcl(CannedAccessControlList.Private);
		// putObjectRequest.setMetadata(metadata);

		// 上传文件。
		ossClient.putObject(putObjectRequest);

		// 设置URL过期时间为10分钟
		Date expiration = new Date(new Date().getTime() + 1000 * 600);
		// 生成以GET方法访问的签名URL,访客可以直接通过浏览器访问相关内容。
		URL url = ossClient.generatePresignedUrl(bucketName_pri, path, expiration);
		Logoutput(String.valueOf(url));

		// 关闭OSSClient。
		ossClient.shutdown();
		// 返回上传成功的文件名
		return path;
	}

	/**
	 * 4.从OSS下载文件
	 * 
	 * @param path       本地储存文件路径
	 * @param orgCode    公司id
	 * @param dir        包名
	 * @param fileName   文件名
	 * @param moudle     模块名
	 * @return 完整文件名
	 */
	public Result<String> downloadFile(String orgCode, String moudle, String dir, String fileName, String path) {
		// <yourObjectName>从OSS下载文件时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
		// String objectName = "8time-v2/test/123.jpg";
		// 创建OSSClient实例。
		OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

		// 下载OSS文件到本地文件。如果指定的本地文件存在会覆盖,不存在则新建。
		ossClient.getObject(
				new GetObjectRequest(bucketName, project_package + orgCode + "/" + moudle + "/" + dir + "/" + fileName),
				new File(path + fileName));

		// 关闭OSSClient。
		ossClient.shutdown();
		// 完整路径的文件名
		Logoutput("objectName:" + project_package + orgCode + "/" + moudle + "/" + dir + "/" + fileName);
		Logoutput("path:" + path + fileName);
		// 返回成功的本地路径
		return ResultUtil.success(path + fileName);
	}

	public Result<BufferedReader> downloadFile(String objectName) throws IOException {
		// 创建OSSClient实例。
		OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

		// ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
		OSSObject ossObject = ossClient.getObject(bucketName, objectName);

		// 读取文件内容。
		System.out.println("Object content:");
		BufferedReader reader = new BufferedReader(new InputStreamReader(ossObject.getObjectContent()));
		while (true) {
			String line = reader.readLine();
			if (line == null)
				break;

			System.out.println("\n" + line);
		}
		// 数据读取完成后,获取的流必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作。
		reader.close();

		// 关闭OSSClient。
		ossClient.shutdown();
		return ResultUtil.data(reader, "下载成功");
	}

	/**
	 * 文件输入流批量上传
	 * 
	 * @param request 获取参数
	 * @param files    批量文件
	 * @return 返回上传成功或失败的信息
	 */
	public String uploadFile(MultipartHttpServletRequest request, List<MultipartFile> files) {

		OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

		String newFileName = null;
		URL url = null;
		try {
			// 上传文件
			CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
					request.getSession().getServletContext());
			// 判断 request 是否有文件上传,即多部分请求
			if (multipartResolver.isMultipart(request)) {
				// 转换成多部分request
				MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
				// 取得request中的所有文件名
				Iterator<String> iter = multiRequest.getFileNames();
				// 此处上传单个文件,如需多个文件改为while循环
				while (iter.hasNext()) {

					// 取得上传文件
					files = multiRequest.getFiles(iter.next());
					if (files != null) {
						// 取得当前上传文件的文件名称
						String myFileName = null;

						for (MultipartFile file : files) {
							myFileName = file.getOriginalFilename();

							// 如果名称不为“”,说明该文件存在,否则说明该文件不存在
							if (StrUtil.isNotEmpty(myFileName.trim())) {
								newFileName = System.currentTimeMillis()
										+ myFileName.substring(myFileName.lastIndexOf("."));
								// 上传客户端文件到oss,如直接上传服务器文件到oss,可使用new FileInputStream( new File("服务器文件路径"))
								ossClient.putObject(bucketName, newFileName, file.getInputStream());
								// 设置URL过期时间为100年。 1s 1h 1d 1y 100y
								Date expiration = new Date(new Date().getTime() + Long.parseLong(expirationTime));
								// 生成以GET方法访问的签名URL,访客可以直接通过浏览器访问相关内容。
								url = ossClient.generatePresignedUrl(bucketName, newFileName, expiration);
								Logoutput(String.valueOf(url));
							}

						}

					}
				}
			}
		} catch (IOException e) {
			e.getStackTrace();
		} finally {
			// 关闭ossClient
			if (null != ossClient)
				ossClient.shutdown();
		}
		return url.toString();

		/*
		 * if (file == null || file.getSize() <= 0) { return
		 * ResultUtil.error("上传的文件为空,请重新选择!"); } else { try {
		 * OSSUtil.uploadFile(userBean.getOrgCode(), className,
		 * file.getOriginalFilename(), file.getInputStream()); } catch (IOException e) {
		 * e.printStackTrace(); } return ResultUtil.success("上传成功"); }
		 */
	}

	/**
	 * 获取8time-v2文件的url
	 * 
	 * @return url地址
	 */
	public String getUrl(String path) {
		// 创建OSSClient实例。
		OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

		// 设置URL过期时间为100年。 1s 1h 1d 1y 10y
		Date expiration = new Date(new Date().getTime() + Long.parseLong(expirationTime));
		// 生成以GET方法访问的签名URL,访客可以直接通过浏览器访问相关内容。
		URL url = ossClient.generatePresignedUrl(bucketName, path, expiration);
		Logoutput(String.valueOf(url));
		// 关闭OSSClient。
		ossClient.shutdown();
		return url.toString();
	}

	/**
	 * 获取8time-v2-private文件的url
	 * 
	 * @return url地址
	 */
	public String getUrlP(String path) {
		// 创建OSSClient实例。
		OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

		// 设置URL过期时间为10分钟。
		Date expiration = new Date(new Date().getTime() + Long.parseLong(expirationTime_pri));
		// 生成以GET方法访问的签名URL,访客可以直接通过浏览器访问相关内容。
		URL url = ossClient.generatePresignedUrl(bucketName, path, expiration);
		Logoutput(String.valueOf(url));
		// 关闭OSSClient。
		ossClient.shutdown();
		return url.toString();
	}

	/**
	 * 删除单个
	 * 
	 * @param objectName 文件名
	 */
	public void delSingleFile(String objectName) {
//		// Endpoint以杭州为例,其它Region请按实际情况填写。
//		String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
//		// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
//		String accessKeyId = "<yourAccessKeyId>";
//		String accessKeySecret = "<yourAccessKeySecret>";
//		String bucketName = "<yourBucketName>";
//		String objectName = "<yourObjectName>";

		// 创建OSSClient实例。
		OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

		// 删除文件。如需删除文件夹,请将ObjectName设置为对应的文件夹名称。如果文件夹非空,则需要将文件夹下的所有object删除后才能删除该文件夹。
		ossClient.deleteObject(bucketName, objectName);

		// 关闭OSSClient。
		ossClient.shutdown();
	}

	/**
	 * 删除多个文件
	 * 
	 * @param keys  需要删除的文件。
	 * @param quiet 返回模式。true表示简单模式,false表示详细模式。默认为详细模式。
	 * @return 删除结果。详细模式下为删除成功的文件列表,简单模式下为删除失败的文件列表。
	 */
	public List<String> delFiles(List<String> keys, boolean quiet) {
//		// Endpoint以杭州为例,其它Region请按实际情况填写。
//		String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
//		// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
//		String accessKeyId = "<yourAccessKeyId>";
//		String accessKeySecret = "<yourAccessKeySecret>";
//		String bucketName = "<yourBucketName>";

		// 创建OSSClient实例。
		OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

		// 删除文件。key等同于ObjectName,表示删除OSS文件时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
//		List<String> keys = new ArrayList<String>();
//		keys.add("key0");
//		keys.add("key1");
//		keys.add("key2");

		DeleteObjectsResult deleteObjectsResult = ossClient
				.deleteObjects(new DeleteObjectsRequest(bucketName).withKeys(keys).withQuiet(quiet));
		List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();

		// 关闭OSSClient。
		ossClient.shutdown();

		return deletedObjects;
	}

	/**
	 * 删除指定前缀(prefix)的文件
	 * 
	 * @param prefix
	 */
	public void delPrefixWith(String prefix) {
//		// Endpoint以杭州为例,其它Region请按实际情况填写。
//		String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
//		// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录
//		// https://ram.console.aliyun.com 创建RAM账号。
//		String accessKeyId = "<yourAccessKeyId>";
//		String accessKeySecret = "<yourAccessKeySecret>";
//		String bucketName = "<yourBucketName>";
//
//		// 指定前缀。
//		final String prefix = "<yourkeyPrefix>";

		// 创建OSSClient实例。
		OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

		// 列举所有包含指定前缀的文件并删除。
		String nextMarker = null;
		ObjectListing objectListing = null;
		do {
			ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName).withPrefix(prefix)
					.withMarker(nextMarker);

			objectListing = ossClient.listObjects(listObjectsRequest);
			if (objectListing.getObjectSummaries().size() > 0) {
				List<String> keys = new ArrayList<String>();
				for (OSSObjectSummary s : objectListing.getObjectSummaries()) {
					Logoutput("key name: " + s.getKey());
					keys.add(s.getKey());
				}
				DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(bucketName).withKeys(keys);
				ossClient.deleteObjects(deleteObjectsRequest);
			}

			nextMarker = objectListing.getNextMarker();
		} while (objectListing.isTruncated());

		// 关闭OSSClient。
		ossClient.shutdown();
	}

	/*
	 * (跨域资源) // Endpoint以杭州为例,其它Region请按实际情况填写。 String endpoint =
	 * "http://oss-cn-hangzhou.aliyuncs.com"; //
	 * 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录
	 * https://ram.console.aliyun.com 创建RAM账号 String accessKeyId =
	 * "<yourAccessKeyId>"; String accessKeySecret = "<yourAccessKeySecret>"; String
	 * bucketName = "<yourBucketName>";
	 * 
	 * // 创建OSSClient实例。 OSS ossClient = new OSSClientBuilder().build(endpoint,
	 * accessKeyId, accessKeySecret);
	 * 
	 * SetBucketCORSRequest request = new SetBucketCORSRequest(bucketName);
	 * 
	 * // 跨域资源共享规则的容器,每个存储空间最多允许10条规则。 ArrayList<CORSRule> putCorsRules = new
	 * ArrayList<CORSRule>();
	 * 
	 * CORSRule corRule = new CORSRule();
	 * 
	 * ArrayList<String> allowedOrigin = new ArrayList<String>(); // 指定允许跨域请求的来源。
	 * allowedOrigin.add( "http://www.b.com");
	 * 
	 * ArrayList<String> allowedMethod = new ArrayList<String>(); //
	 * 指定允许的跨域请求方法(GET/PUT/DELETE/POST/HEAD)。 allowedMethod.add("GET");
	 * 
	 * ArrayList<String> allowedHeader = new ArrayList<String>(); //
	 * 是否允许预取指令(OPTIONS)中Access-Control-Request-Headers头中指定的Header。
	 * allowedHeader.add("x-oss-test");
	 * 
	 * ArrayList<String> exposedHeader = new ArrayList<String>(); //
	 * 指定允许用户从应用程序中访问的响应头。 exposedHeader.add("x-oss-test1"); //
	 * AllowedOrigins和AllowedMethods最多支持一个星号(*)通配符。星号(*)表示允许所有的域来源或者操作。
	 * corRule.setAllowedMethods(allowedMethod);
	 * corRule.setAllowedOrigins(allowedOrigin); //
	 * AllowedHeaders和ExposeHeaders不支持通配符。 corRule.setAllowedHeaders(allowedHeader);
	 * corRule.setExposeHeaders(exposedHeader); //
	 * 指定浏览器对特定资源的预取(OPTIONS)请求返回结果的缓存时间,单位为秒。 corRule.setMaxAgeSeconds(10);
	 * 
	 * // 最多允许10条规则。 putCorsRules.add(corRule); // 已存在的规则将被覆盖。
	 * request.setCorsRules(putCorsRules); ossClient.setBucketCORS(request);
	 * 
	 * // 关闭OSSClient。 ossClient.shutdown();
	 */

	public void download(String url, String savePath) {
		// Endpoint以杭州为例,其它Region请按实际情况填写。
//		String endpoint = "http://oss-cn-shenzhen.aliyuncs.com";
//		// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录
//		// https://ram.console.aliyun.com 创建RAM账号。
//		String accessKeyId = "LTAI4FuaShJWQ1dggsFWG5CC";
//		String accessKeySecret = "EJ6qToT4T4u0B5Rb6qrta9WkyGHvGR";
//		String bucketName = "8time-v2";
//		String objectName = "8timer2.0/117/test/测试.pdf";

		OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
//				String url = "http://8time-v2.oss-cn-shenzhen.aliyuncs.com/8timer2.0/310/qyxx/filepath/158872957193802f4a85a-9dd9-483a-9049-86fac5c73bd5.pdf?Expires=4747952308&OSSAccessKeyId=LTAI4FuaShJWQ1dggsFWG5CC&Signature=z%2FNIX0RrxnLuBLAS9olPpxxsCrI%3D";
		try {
			// 带进度条的下载。
			ObjectMetadata a = ossClient.getObject(new GetObjectRequest(new URL(url), null), new File(savePath));
			System.err.println(a);
//					new File("C:\\Users\\Lenovo\\Desktop\\8小时\\test2.pdf"));
//					// 带进度条的下载。
//					ossClient.getObject(new GetObjectRequest(bucketName, objectName).<GetObjectRequest>withProgressListener(
//							new GetObjectProgressListener()), new File("C:\\Users\\Lenovo\\Desktop\\8小时\\test.pdf"));
		} catch (Exception e) {
			e.printStackTrace();
		}
		// 关闭OSSClient。
		ossClient.shutdown();
	}

	static class GetObjectProgressListener implements ProgressListener {
		private long bytesRead = 0;
		private long totalBytes = -1;
		private boolean succeed = false;

		@Override
		public void progressChanged(ProgressEvent progressEvent) {
			long bytes = progressEvent.getBytes();
			ProgressEventType eventType = progressEvent.getEventType();
			switch (eventType) {
			case TRANSFER_STARTED_EVENT:
				System.out.println("Start to download......");
				break;
			case RESPONSE_CONTENT_LENGTH_EVENT:
				this.totalBytes = bytes;
				System.out.println(this.totalBytes + " bytes in total will be downloaded to a local file");
				break;
			case RESPONSE_BYTE_TRANSFER_EVENT:
				this.bytesRead += bytes;
				if (this.totalBytes != -1) {
					int percent = (int) (this.bytesRead * 100.0 / this.totalBytes);
					System.out.println(bytes + " bytes have been read at this time, download progress: " + percent
							+ "%(" + this.bytesRead + "/" + this.totalBytes + ")");
				} else {
					System.out.println(bytes + " bytes have been read at this time, download ratio: unknown" + "("
							+ this.bytesRead + "/...)");
				}
				break;
			case TRANSFER_COMPLETED_EVENT:
				this.succeed = true;
				System.out.println("Succeed to download, " + this.bytesRead + " bytes have been transferred in total");
				break;
			case TRANSFER_FAILED_EVENT:
				System.out.println("Failed to download, " + this.bytesRead + " bytes have been transferred");
				break;
			default:
				break;
			}
		}

		public boolean isSucceed() {
			return succeed;
		}
	}

	@Value("${config-8timer.environmental-science}")
	public String environmental_science;
	
	public void Logoutput(String science) {
		
		if(!("pro").equals(environmental_science)) {
			
			System.out.println(science);
		}else {
			System.out.println("");
		}
		
	}
}