package org.springblade.wx.controller;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.oss.model.BladeFile;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.modules.resource.builder.oss.OssBuilder;
import org.springblade.wx.config.ConfigForClient;
import org.springblade.wx.constant.MiniProgramType;
import org.springblade.wx.constant.WeChatApi;
import org.springblade.wx.dto.DataDto;
import org.springblade.wx.dto.JumpWxa;
import org.springblade.wx.dto.SchemeDto;
import org.springblade.wx.service.WeChatService;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author cy-computer
 */
@RestController
@Slf4j
@RequestMapping("/wx-app")
@Api(tags = "微信小程序登录模块")
@AllArgsConstructor
public class WxAppController {

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

	private ConfigForClient configForClient;
	private StringRedisTemplate stringRedisTemplate;
	private WeChatService weChatService;


	private static final String ACCESS_TOKEN = "access_token:";


	@ApiOperation("获取开发数据")
	@PostMapping("/getOpenData")
	public R getOpenData(@RequestBody DataDto dataDto) {
		byte[] key = Base64.getDecoder().decode(dataDto.getSessionKey().replaceAll(" ", "+"));
		byte[] iv = Base64.getDecoder().decode(dataDto.getIv().replaceAll(" ", "+"));
		byte[] content = Base64.getDecoder().decode(dataDto.getEncryptedData().replaceAll(" ", "+"));
		AES aes = new AES(Mode.CBC, Padding.PKCS5Padding, key, iv);
		return R.data(new String(aes.decrypt(content)));
	}

	@ApiOperation("获取小程序码")
	@GetMapping("/getCode")
	public R getCode(String scene,MiniProgramType type,String page) throws IOException {
		HttpResponse unlimitCode = weChatService.getUnlimitCode(scene, type, page);
		byte[] bytes = unlimitCode.bodyBytes();
		BladeFile bladeFile = this.uploadImage(bytes);
		return R.data(bladeFile);
	}

	@ApiOperation("获取access_token")
	@GetMapping("/getAccessToken")
	public R getAccessTokenOfClient() {

		String appId = configForClient.getAppId();
		String appSecret = configForClient.getAppSecret();
		String accessTokenKey = ACCESS_TOKEN + appId;
		//从缓存中获取
		String accessToken = stringRedisTemplate.opsForValue().get(accessTokenKey);
		if (StringUtil.isBlank(accessToken)) {
			StringBuilder sb = new StringBuilder("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=");
			sb.append(appId).append("&secret=").append(appSecret);
			String url = sb.toString();
			String s = HttpUtil.get(url);
			JSONObject jsonObject = JSON.parseObject(s);
			accessToken = jsonObject.getString("access_token");
			if (StringUtil.isNotBlank(accessToken)) {
				stringRedisTemplate.opsForValue().set(accessTokenKey, accessToken, 7000, TimeUnit.SECONDS);
			}
		}
		return R.data(accessToken);
	}

	@ApiOperation("获取GenerateScheme")
	@GetMapping("/getGenerateScheme")
	public R getGenerateScheme(String path, String query) {
		SchemeDto schemeDto = new SchemeDto();
		schemeDto.setJump_wxa(new JumpWxa(path,query));
		String accessToken = (String)this.getAccessTokenOfClient().getData();
		String url = "https://api.weixin.qq.com/wxa/generatescheme?access_token=" + accessToken;

		String s = HttpRequest.post(url)
			.header(Header.CONTENT_TYPE, "application/json")
			.body(JSON.toJSONString(schemeDto))
			.execute().body();
		JSONObject jsonObject = JSON.parseObject(s);
		return R.data(jsonObject);
	}

	@ApiOperation("获取openId")
	@GetMapping("/getOpenId")
	public R getOpenId(String code,String type) {
		//默认获取C端的openId
		if (StringUtil.isBlank(type)) {
			type = "CLIENT";
		}
		return R.data(weChatService.getOpenId(code, MiniProgramType.valueOf(type)));
	}


	@ApiOperation("获取小程序码")
	@GetMapping("/createWxaQrCode")
	public R createWxaQrCode(String path,@RequestParam String type) throws IOException {
		//根据类型获取accessToken
		String accessToken = weChatService.fetchAccessToken(MiniProgramType.valueOf(type));
		Assert.notNull(accessToken, "获取accessToken失败");

		String url = WeChatApi.createWxaQrCode.buildUrl(accessToken);
		RestTemplate rest = new RestTemplate();


		Map<String,Object> param = new HashMap<>(4);
		param.put("path", path);
		param.put("width", 430);

		MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
		HttpEntity requestEntity = new HttpEntity(param, headers);
		ResponseEntity<byte[]> entity = rest.exchange(url, HttpMethod.POST, requestEntity, byte[].class, new Object[0]);
		log.info("调用小程序生成微信永久二维码URL接口返回结果:" + entity.getBody());

		byte[] result = entity.getBody();
		BladeFile bladeFile = this.uploadImage(result);
		return R.data(bladeFile);
	}

	private BladeFile uploadImage(byte[] bytes) throws IOException {
		BladeFile bladeFile = new BladeFile();

		InputStream inputStream = null;
		try {
			inputStream = new ByteArrayInputStream(bytes);
			MultipartFile multipartFile =new MockMultipartFile("file", "shopQrCode.jpg", "text/plain", inputStream);
			//上传到对象存储
			bladeFile = ossBuilder.template().putFile(multipartFile.getOriginalFilename(), multipartFile.getInputStream());
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			if (inputStream != null) {
				inputStream.close();
			}
		}
		return bladeFile;
	}

	private String replaceEnter(String str){
		String reg ="[\n-\r]";
		Pattern p = Pattern.compile(reg);
		Matcher m = p.matcher(str);
		return m.replaceAll("");
	}

}
