package com.neusoft.smart.pos.gateway.controller;

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.*;
import com.neusoft.smart.pos.dto.oss.UploadNotifyRequest;
import com.neusoft.smart.pos.framework.config.RabbitExchangeConfiguration;
import com.neusoft.smart.pos.framework.constants.CommonErrorCode;
import com.neusoft.smart.pos.framework.constants.SignatureConstants;
import com.neusoft.smart.pos.framework.dto.ResponseData;
import com.neusoft.smart.pos.framework.exception.BusinessCommonException;
import com.neusoft.smart.pos.framework.utils.IdGenerateUtils;
import com.neusoft.smart.pos.framework.utils.LocalDateTimeUtils;
import com.neusoft.smart.pos.framework.utils.SignatureUtils;
import com.neusoft.smart.pos.mq.rabbitmq.RabbitMQSender;

import io.swagger.annotations.ApiOperation;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/unionService/Reconciliation")
public class OssReconciliationController {
	
	@Value("${smart.pos.constant.oss.endpoint}")
	private String endpoint;
	
	@Value("${smart.pos.constant.oss.accessId}")
	private String accessId;
	
	@Value("${smart.pos.constant.oss.accessKey}")
	private String accessKey;
	
	@Value("${smart.pos.constant.oss.host}")
	private String host;

	@Value("${smart.pos.constant.oss.bucketName}")
	private String bucketName;

	@Value("${smart.pos.constant.oss.url.host}")
	private String urlHost;

	private static final int MAX_FILE_NUM = 7;//TODO
	private static final String CMB_BILL_UPLOAD_DIR = "bill/CMB/";

	@Autowired
	private RabbitMQSender rabbitMQSender;

	@PostMapping(value = "/Billupload")
	public ResponseData<JSONObject> getSignature(String mcode, String timestamp, String nonce, String sign, MultipartFile file, HttpServletResponse response) throws IOException {
		// 验签
        HashMap<String, String> data = new HashMap<>();
        data.put("mcode",mcode);
        data.put("timestamp",timestamp);
        data.put("nonce",nonce);
		data.put("sign",sign);
		if (!SignatureUtils.isSignatureValid(data, SignatureConstants.CMB_SIGN_KTY)) {
			throw new BusinessCommonException(CommonErrorCode.SIGN_VALIDATE_ERROR);
		}
        String dir = "";
		String newFileName = "";
        if (file != null) {
            String fileName = file.getOriginalFilename();//获取上传原图片名称
            newFileName = LocalDateTimeUtils.getDateTime("yyyyMMddHHmmss") + "_" + IdGenerateUtils.randomNumber(6) + fileName.substring(fileName.lastIndexOf("."));//生成保存在服务器的文件名称，延用原后缀名
            try {
                String res = upload(CMB_BILL_UPLOAD_DIR + newFileName, file.getInputStream());
				dir = "http://" + bucketName + "." + endpoint + "/" + CMB_BILL_UPLOAD_DIR;
            } catch (IOException e) {
                e.printStackTrace();
                throw new BusinessCommonException(CommonErrorCode.UPLOAD_FILE_FAILED);
            }
        } else {
            throw new BusinessCommonException(CommonErrorCode.UPLOAD_FILE_EMPTY);
        }

        Map<String, String> respMap = new LinkedHashMap<>();
        respMap.put("dir", CMB_BILL_UPLOAD_DIR);
        respMap.put("filename", newFileName);
        if(dir.endsWith("/")) {
			respMap.put("key", dir + newFileName);
		} else {
			respMap.put("key", dir + "/" + newFileName);
		}
		JSONObject ja1 = JSONObject.fromObject(respMap);
		//response.setHeader("Access-Control-Allow-Origin", "*");
		response.setHeader("Access-Control-Allow-Methods", "GET, POST");
		return new ResponseData<>(ja1);
	}

	@PostMapping(value = "/BillNotify")
	public ResponseData<?> notify(@RequestBody UploadNotifyRequest request, HttpServletResponse response) throws IOException {
		// 验签
        String dir = request.getDir();
        String result = request.getResult();
        String message = request.getMessage();
        String key = request.getKey();
		HashMap<String, String> data = new HashMap<>();
		data.put("mcode",request.getMcode());
		data.put("dir",dir);
		data.put("filename",request.getFilename());
		data.put("key",key);
		data.put("action",request.getAction());
		data.put("timestamp",request.getTimestamp());
		data.put("nonce",request.getNonce());
		if(!result.isEmpty()) {
			data.put("result",result);
		}
		if(!message.isEmpty()) {
			data.put("message",message);
		}
		data.put("sign",request.getSign());
		if (!SignatureUtils.isSignatureValid(data, SignatureConstants.CMB_SIGN_KTY)) {
			throw new BusinessCommonException(CommonErrorCode.SIGN_VALIDATE_ERROR);
		}

		if(result.equals("true")) { // 上传成功
			// TODO step1: 记录log
			// step2: 检查dir目录下文件数目,保留最新的7个文件，把其他文件删除
			OSSClient ossClient = new OSSClient(endpoint, accessId, accessKey);
			// 构造ListObjectsRequest请求。
			ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName);
			listObjectsRequest.setDelimiter("/"); // 设置正斜线（/）为文件夹的分隔符。
			if(dir.startsWith("/")) {
				dir = dir.substring(1);
			}
			if(!dir.endsWith("/")) {
				dir = dir + "/";
			}
			listObjectsRequest.setPrefix(dir); // 列出dir目录下的所有文件和文件夹。
			ObjectListing listing = ossClient.listObjects(listObjectsRequest);
			List<OSSObjectSummary> ossObjectSummaries = listing.getObjectSummaries();
			if(ossObjectSummaries.size() > MAX_FILE_NUM ) { // objectSummaries的列表中给出的是fun目录下的文件(不包含子文件夹和子文件夹下的文件)
				for (int i = ossObjectSummaries.size() - MAX_FILE_NUM-1; i >= 0; i--) {
					ossClient.deleteObject(bucketName, ossObjectSummaries.get(i).getKey());
				}
			}
			String objectName = dir + request.getFilename();
			boolean fileExist = ossClient.doesObjectExist(bucketName, objectName);
			ossClient.shutdown();
			// step3: 发出通知，接口入参的action可以作为通知标识的一部分，参数传递：key
			if(fileExist) {
				rabbitMQSender.sendMessage(RabbitExchangeConfiguration.FANOUT_EXCHANGE_FILE_UPLOADED_NOTIFY, "", objectName);
			} else {
				throw new BusinessCommonException(CommonErrorCode.NOTIFIED_FILE_EMPTY);
			}
		} else { // 上传失败，记录失败原因
			if(!result.isEmpty()) {
				// TODO 怎么记录？？
			}
		}
		return new ResponseData<>();
	}

	public String upload(String fileName, InputStream instream) {
		String resultStr = "";
		OSSClient client = new OSSClient(endpoint, accessId, accessKey);
		try {
			// 创建上传Object的Metadata
			ObjectMetadata objectMetadata = new ObjectMetadata();
			// 上传文件 (上传文件流的形式)
			PutObjectResult putResult = client.putObject(bucketName, fileName, instream, objectMetadata);
			// 解析结果
			resultStr = putResult.getETag();
		} catch (Exception e) {
			e.printStackTrace();

		} finally {
			try {
				if (instream != null) {
					instream.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return resultStr;
	}

	public String getUrl(String key, String option) {
		if (StringUtils.isEmpty(key))
			return "";
		return "http://" + bucketName + "." + endpoint + "/" + key + option;
	}
}
