package com.apobates.forum.trident.fileupload;

import java.io.IOException;
import java.util.Map;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
/**
 * 站外存储上传的图片
 * 
 * @author xiaofanku
 * @since 20191024
 */
public class OutsideImageStorage implements ImageStorageExecutor{
	private final String imageBucketDomain;
	private final String uploadImageDirectName;
	private final String imageBucketUploadURL;
	private final String imageBucketUploadInputFileName;
	private final static Logger logger = LoggerFactory.getLogger(OutsideImageStorage.class);
	
	/**
	 * 
	 * @param imageBucketDomain              站外的访问域名,例:http://x.com
	 * @param uploadImageDirectName          站外保存图片的目录
	 * @param imageBucketUploadURL           站外上传程序的访问地址,例:http://x.com/y
	 * @param imageBucketUploadInputFileName 站外上传程序接受的type=file输入项的名称
	 */
	public OutsideImageStorage(String imageBucketDomain, String uploadImageDirectName, String imageBucketUploadURL, String imageBucketUploadInputFileName) {
		if(logger.isDebugEnabled()){
			logger.debug("[ImageStorageExecutor]现在是站外存储");
		}
		this.imageBucketDomain = imageBucketDomain;
		this.uploadImageDirectName = uploadImageDirectName;
		this.imageBucketUploadURL = imageBucketUploadURL;
		this.imageBucketUploadInputFileName = imageBucketUploadInputFileName;
	}

	@Override
	public String imageBucketDomain() {
		return imageBucketDomain;
	}

	@Override
	public String uploadImageDirectName() {
		return uploadImageDirectName;
	}

	public String getImageBucketUploadURL() {
		return imageBucketUploadURL;
	}

	public String getImageBucketUploadInputFileName() {
		return imageBucketUploadInputFileName;
	}
	
	/**
	 * 如果FormBean不使用MultipartFile此方法不建议调用
	 */
	@Override
	public Optional<String> store(MultipartFile file) throws IOException {
		if(null==file || file.isEmpty()){
			logger.info("[AFU][OU] 文件不存在或不可用");
			return Optional.empty(); //Result.failure("文件不存在或不可用");
		}
		HttpHeaders parts = new HttpHeaders();  
		parts.setContentType(MediaType.TEXT_PLAIN);
		final ByteArrayResource byteArrayResource = new ByteArrayResource(file.getBytes()) {
			@Override
			public String getFilename() {
				return file.getOriginalFilename();
			}
		};
		final HttpEntity<ByteArrayResource> partsEntity = new HttpEntity<>(byteArrayResource, parts);
		//
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.MULTIPART_FORM_DATA);
		
		MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
		body.add(imageBucketUploadInputFileName, partsEntity);
		HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
		
		RestTemplate restTemplate = new RestTemplate();
		String responseBody = restTemplate.postForEntity(imageBucketUploadURL, requestEntity, String.class).getBody();
		return parseFileURL(responseBody);
	}

	private Optional<String> parseFileURL(String responseBody)throws IOException{
		logger.info("[AFU][AF]2> 响应内容: "+responseBody);
		if(responseBody == null){
			logger.info("[AFU][AF]3> 上传失败");
			throw new IOException("上传失败");
		}
		Map<String, Object> rbMap = new Gson().fromJson(responseBody, new TypeToken<Map<String, Object>>() {}.getType());
		if(null==rbMap || rbMap.isEmpty()){
			logger.info("[AFU][AF]4> 解析远程响应内容失败");
			throw new IOException("解析远程响应内容失败");
		}
		if(rbMap.containsKey("error")){
			@SuppressWarnings("unchecked")
			Map<String,String> tmp = (Map<String,String>)rbMap.get("error");
			logger.info("[AFU][AF]5> 上传操作因: "+ tmp.get("message")+"异常而中止");
			throw new IOException("上传操作因: "+ tmp.get("message")+"异常而中止");
		}
		//
		try{
			String fileVisitPath = rbMap.get("url").toString();
			logger.info("[AFU][AF]6> 图片访问地址: "+fileVisitPath);
			return Optional.of(fileVisitPath);
		}catch(NullPointerException | ClassCastException e){
			throw new IOException("获取上传图片地址失败: "+ e.getMessage());
		}
	}
}
