
package org.springblade.modules.resource.service;

import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.oss.OssTemplate;
import org.springblade.core.oss.enums.OssEnum;
import org.springblade.core.oss.props.OssProperties;
import org.springblade.core.oss.rule.BladeOssRule;
import org.springblade.core.oss.rule.OssRule;
import org.springblade.core.tool.api.ResultCode;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.resource.pojo.entity.Oss;
import org.springblade.modules.resource.rule.context.OssContext;
import org.springframework.stereotype.Service;

import java.util.Map;

/**
 * OSS流程编排服务 (替代 LiteFlow ossChain)
 *
 * 原 LiteFlow 流程:
 * THEN(
 *   preOssRule,
 *   SWITCH(ossCacheRule).TO(
 *     ossReadRule,
 *     THEN(ossDataRule, SWITCH(ossBuildRule).TO(...), ossTemplateRule)
 *   ),
 *   finallyOssRule
 * )
 *
 * @author Chill
 */
@Service
public class OssChainService {

	/**
	 * 执行 OSS 构建流程
	 *
	 * @param tenantId   租户ID
	 * @param ossContext OSS上下文
	 * @return OssTemplate
	 */
	public OssTemplate execute(String tenantId, OssContext ossContext) {
		try {
			// 1. preOssRule - 前置处理
			preOssProcess(tenantId, ossContext);

			// 2. SWITCH(ossCacheRule) - 缓存判断
			if (ossContext.getIsCached()) {
				// ossReadRule - 读取缓存
				ossReadProcess(tenantId, ossContext);
			} else {
				// ossNewRule 分支
				// 2.1 ossDataRule - 数据处理
				ossDataProcess(ossContext);

				// 2.2 SWITCH(ossBuildRule) - 根据类型构建
				ossBuildProcess(ossContext);

				// 2.3 ossTemplateRule - 模板校验
				ossTemplateProcess(ossContext);
			}

			// 3. finallyOssRule - 后置处理
			finallyOssProcess(tenantId, ossContext);

			return ossContext.getOssTemplate();
		} catch (Exception e) {
			throw new ServiceException("未获取到对应的对象存储配置");
		}
	}

	/**
	 * preOssRule - OSS构建前置处理
	 */
	private void preOssProcess(String tenantId, OssContext ossContext) {
		Map<String, Oss> ossPool = ossContext.getOssPool();
		Map<String, OssTemplate> templatePool = ossContext.getTemplatePool();
		Oss oss = ossContext.getOss();
		Oss ossCached = ossPool.get(tenantId);
		OssTemplate template = templatePool.get(tenantId);

		// 若为空或者不一致,则重新加载
		if (Func.hasEmpty(template, ossCached)
			|| !Func.equalsSafe(oss.getEndpoint(), ossCached.getEndpoint())
			|| !Func.equalsSafe(oss.getTransformEndpoint(), ossCached.getTransformEndpoint())
			|| !Func.equalsSafe(oss.getAccessKey(), ossCached.getAccessKey())) {
			ossContext.setIsCached(Boolean.FALSE);
		} else {
			ossContext.setIsCached(Boolean.TRUE);
		}
	}

	/**
	 * ossReadRule - 从缓存读取
	 */
	private void ossReadProcess(String tenantId, OssContext ossContext) {
		// 该规则为空实现,只做标记
	}

	/**
	 * ossDataRule - 构建 OssRule 数据对象
	 */
	private void ossDataProcess(OssContext ossContext) {
		// OssRule 是接口,使用 BladeOssRule 实现
		// 从 OssProperties 中获取租户模式配置
		OssProperties ossProperties = ossContext.getOssProperties();
		Boolean tenantMode = ossProperties.getTenantMode();
		OssRule ossRule = new BladeOssRule(tenantMode != null ? tenantMode : false);
		ossContext.setOssRule(ossRule);
	}

	/**
	 * ossBuildRule - 根据 OSS 类型构建对应的 OssTemplate
	 */
	private void ossBuildProcess(OssContext ossContext) {
		Oss oss = ossContext.getOss();
		OssRule ossRule = ossContext.getOssRule();
		OssProperties ossProperties = ossContext.getOssProperties();

		// 从Oss实体设置OssProperties的值
		ossProperties.setEndpoint(oss.getEndpoint());
		ossProperties.setTransformEndpoint(oss.getTransformEndpoint());
		ossProperties.setAccessKey(oss.getAccessKey());
		ossProperties.setSecretKey(oss.getSecretKey());
		ossProperties.setBucketName(oss.getBucketName());

		OssTemplate ossTemplate;

		try {
			if (oss.getCategory() == OssEnum.MINIO.getCategory()) {
				// MinIO - 创建 MinioClient 并构建模板
				io.minio.MinioClient minioClient = io.minio.MinioClient.builder()
					.endpoint(oss.getEndpoint())
					.credentials(oss.getAccessKey(), oss.getSecretKey())
					.build();
				ossTemplate = new org.springblade.core.oss.MinioTemplate(minioClient, ossRule, ossProperties);
			} else if (oss.getCategory() == OssEnum.QINIU.getCategory()) {
				// 七牛云 - 创建 Auth, UploadManager, BucketManager 并构建模板
				com.qiniu.util.Auth auth = com.qiniu.util.Auth.create(oss.getAccessKey(), oss.getSecretKey());
				com.qiniu.storage.Region region = com.qiniu.storage.Region.autoRegion();
				com.qiniu.storage.Configuration cfg = new com.qiniu.storage.Configuration(region);
				com.qiniu.storage.UploadManager uploadManager = new com.qiniu.storage.UploadManager(cfg);
				com.qiniu.storage.BucketManager bucketManager = new com.qiniu.storage.BucketManager(auth, cfg);
				ossTemplate = new org.springblade.core.oss.QiniuTemplate(auth, uploadManager, bucketManager, ossProperties, ossRule);
			} else if (oss.getCategory() == OssEnum.ALI.getCategory()) {
				// 阿里云 OSS - 创建 OSS 客户端并构建模板
				com.aliyun.oss.OSSClient ossClient = (com.aliyun.oss.OSSClient) new com.aliyun.oss.OSSClientBuilder().build(
					oss.getEndpoint(),
					oss.getAccessKey(),
					oss.getSecretKey()
				);
				ossTemplate = new org.springblade.core.oss.AliossTemplate(ossClient, ossProperties, ossRule);
			} else if (oss.getCategory() == OssEnum.TENCENT.getCategory()) {
				// 腾讯云 COS - 创建 COSClient 并构建模板
				com.qcloud.cos.COSClient cosClient = createTencentCosClient(oss);
				ossTemplate = new org.springblade.core.oss.TencentCosTemplate(cosClient, ossProperties, ossRule);
			} else if (oss.getCategory() == OssEnum.HUAWEI.getCategory()) {
				// 华为云 OBS - 创建 ObsClient 并构建模板
				com.obs.services.ObsClient obsClient = new com.obs.services.ObsClient(
					oss.getAccessKey(),
					oss.getSecretKey(),
					oss.getEndpoint()
				);
				ossTemplate = new org.springblade.core.oss.HuaweiObsTemplate(obsClient, ossProperties, ossRule);
			} else if (oss.getCategory() == OssEnum.AMAZONS3.getCategory()) {
				// Amazon S3 - 创建 AmazonS3 客户端并构建模板
				com.amazonaws.services.s3.AmazonS3 s3Client = createAmazonS3Client(oss);
				ossTemplate = new org.springblade.core.oss.S3Template(s3Client, ossRule, ossProperties);
			} else {
				throw new ServiceException("未找到OSS配置");
			}
		} catch (Exception e) {
			throw new ServiceException("创建OSS客户端失败");
		}

		ossContext.setOssTemplate(ossTemplate);
	}

	/**
	 * 创建腾讯云COS客户端
	 */
	private com.qcloud.cos.COSClient createTencentCosClient(Oss oss) {
		com.qcloud.cos.auth.BasicCOSCredentials cred = new com.qcloud.cos.auth.BasicCOSCredentials(
			oss.getAccessKey(),
			oss.getSecretKey()
		);
		com.qcloud.cos.region.Region region = new com.qcloud.cos.region.Region(
			Func.isNotBlank(oss.getRegion()) ? oss.getRegion() : "ap-guangzhou"
		);
		com.qcloud.cos.ClientConfig clientConfig = new com.qcloud.cos.ClientConfig(region);
		return new com.qcloud.cos.COSClient(cred, clientConfig);
	}

	/**
	 * 创建Amazon S3客户端
	 */
	private com.amazonaws.services.s3.AmazonS3 createAmazonS3Client(Oss oss) {
		com.amazonaws.auth.AWSCredentials credentials = new com.amazonaws.auth.BasicAWSCredentials(
			oss.getAccessKey(),
			oss.getSecretKey()
		);

		com.amazonaws.ClientConfiguration clientConfiguration = new com.amazonaws.ClientConfiguration();
		clientConfiguration.setSignerOverride("AWSS3V4SignerType");

		String region = Func.isNotBlank(oss.getRegion())
			? oss.getRegion()
			: com.amazonaws.regions.Regions.DEFAULT_REGION.name();

		return com.amazonaws.services.s3.AmazonS3ClientBuilder.standard()
			.withEndpointConfiguration(new com.amazonaws.client.builder.AwsClientBuilder.EndpointConfiguration(
				oss.getEndpoint(),
				region
			))
			.withPathStyleAccessEnabled(true)
			.withClientConfiguration(clientConfiguration)
			.withCredentials(new com.amazonaws.auth.AWSStaticCredentialsProvider(credentials))
			.build();
	}

	/**
	 * ossTemplateRule - OSS接口读取校验
	 */
	private void ossTemplateProcess(OssContext ossContext) {
		OssTemplate ossTemplate = ossContext.getOssTemplate();
		if (Func.isEmpty(ossTemplate)) {
			throw new ServiceException("OSS接口读取失败!");
		}
	}

	/**
	 * finallyOssRule - OSS构建后置处理
	 */
	private void finallyOssProcess(String tenantId, OssContext ossContext) {
		Map<String, Oss> ossPool = ossContext.getOssPool();
		Map<String, OssTemplate> templatePool = ossContext.getTemplatePool();

		if (ossContext.getIsCached()) {
			OssTemplate template = templatePool.get(tenantId);
			ossContext.setOssTemplate(template);
		} else {
			Oss oss = ossContext.getOss();
			OssTemplate template = ossContext.getOssTemplate();
			if (Func.hasEmpty(template, oss)) {
				throw new ServiceException("OSS接口读取失败!");
			} else {
				templatePool.put(tenantId, template);
				ossPool.put(tenantId, oss);
			}
		}
	}
}
