package org.springblade.face.controller;


import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FileUtils;
import org.springblade.common.unciom.UnicomUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.exception.ServiceException;
import org.springblade.core.tool.support.Kv;
import org.springblade.core.tool.utils.Func;
import org.springblade.face.data.FaceIdentifyData;
import org.springblade.face.data.FaceRegisteredData;
import org.springblade.face.data.FaceRemoveData;
import org.springblade.face.util.Base64Util;
import org.springblade.face.util.FileUtil;
import org.springblade.face.util.HttpUtils;
import org.springblade.modules.auth.enums.UserEnum;
import org.springblade.modules.auth.utils.TokenUtil;
import org.springblade.modules.system.entity.Tenant;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.entity.UserInfo;
import org.springblade.modules.system.service.ITenantService;
import org.springblade.modules.system.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.xiaoymin.knife4j.core.util.StrUtil;

import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 人脸识别
 * </p>
 *
 * @author zbc
 * @since 2021-06-24
 */
@RestController
@RequestMapping("CustomFace")
@Slf4j
@Api(value = "人脸识别(自主平台)管理", tags = "人脸识别(自主平台)接口")
public class CustomFaceController {

	@Autowired
	private IUserService userService;

	@Autowired
	private ITenantService tenantService;


	@Value("${blade.file.uploadFace}")
	private String picDir;


	@PostMapping("/uploadFaceImg")
	@ApiOperation(value = "人脸照片上传", notes = "人脸照片上传")
	public R uploadFile(MultipartFile file) {
		if (null == file) {
			return R.fail("文件不能为空");
		}
		//图片上传
		String oFileName = file.getOriginalFilename();
		String fileSuffix = oFileName.substring(oFileName.lastIndexOf("."));

		if (!".jpg".equalsIgnoreCase(fileSuffix) &&
			!".jpeg".equalsIgnoreCase(fileSuffix) &&
			!".gif".equalsIgnoreCase(fileSuffix) &&
			!".png".equalsIgnoreCase(fileSuffix)
		) {
			return R.fail("只能上传jpg/jpeg/gif/png类型的文件");
		}
		if (file.getSize() > 1024 * 1000 * 100) {
			return R.fail("附件不得大于100M");
		}
		String tempFileName = UUID.randomUUID().toString() + fileSuffix;
		File f = new File(picDir + tempFileName);
		try {
			FileUtils.copyInputStreamToFile(file.getInputStream(), f);
		} catch (IOException e) {
			e.printStackTrace();
		}
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("url", "uploads/face/" + tempFileName);
		return R.data(jsonObject);
	}


	@Value("${customAI.groupId}")
	private String groupId;



	@ApiOperation("创建用户组")
	@RequestMapping(value = "/groupAdd", method = RequestMethod.POST)
	public R groupAdd() {
		String url = "https://opapi.bol.wo.cn/aicgi/face-api/v3/group/add";
		//String url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/group/add";
		String faceGroupId = groupId;
		try {
			String accessToken = getAccessToken();
			if (!"FAIL".equals(accessToken) && StrUtil.isNotBlank(accessToken)) {
				Map<String, Object> map = new HashMap<>();
				map.put("group_id", faceGroupId);
				String param = JSON.toJSONString(map);

				Map<String, String> headers = new HashMap<>();
				headers.put("access_token", accessToken);

				String result = HttpUtils.doPostByJson(url, headers, param);
				JSONObject parse = JSONObject.parseObject(result);
				return R.data(parse);
			}
			return R.fail("鉴权失败");
		} catch (Exception e) {
			e.printStackTrace();
			return R.fail("创建用户组失败");
		}
	}



	@ApiOperation("人脸注册")
	@RequestMapping(value = "/faceRegistered", method = RequestMethod.POST)
	public R faceRegistered(@RequestBody FaceRegisteredData faceRegisteredData) {
		log.info("faceRegistered : {}", faceRegisteredData);
		if (StrUtil.isBlank(faceRegisteredData.getImgPath())) {
			return R.fail("图片相对路径不能为空");
		}
		if (StrUtil.isBlank(faceRegisteredData.getSysUserId())) {
			return R.fail("用户id不能为空");
		}
		try {
			//String filePath = "D:/boyuan/work/img/c1a.jpg";
			//byte[] imgData = FileUtil.readFileByBytes(filePath);
			byte[] imgData = FileUtil.readFileByBytes(picDir + faceRegisteredData.getImgPath());
			String imgStr = Base64Util.encode(imgData);

			User user = userService.getById(faceRegisteredData.getSysUserId());
			String faceUserId = "faceBY" + faceRegisteredData.getSysUserId();
			String faceGroupId = groupId;
			user.setFaceGroupId(faceGroupId);
			user.setFaceUserId(faceUserId);
			user.setFaceImg(faceRegisteredData.getImgPath());
			String accessToken = getAccessToken();

			if (!"FAIL".equals(accessToken) && StrUtil.isNotBlank(accessToken)) {
				String url = "https://opapi.bol.wo.cn/aicgi/face-api/v3/face/add";
				//String url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/user/add";

				Map<String, Object> map = new HashMap<>();
				map.put("image", imgStr);
				map.put("group_id", faceGroupId);
				map.put("user_id", faceUserId);
				map.put("image_type", "BASE64");
				map.put("action_type", "REPLACE");
				map.put("liveness_control", "NORMAL");
				map.put("quality_control", "LOW");

				Map<String, String> headers = new HashMap<>();
				headers.put("access_token", accessToken);

				String param = JSON.toJSONString(map);
				String result = HttpUtils.doPostByJson(url, headers, param);
				JSONObject parse = JSONObject.parseObject(result);
				log.info("人脸注册返回结果 === result {},parse {}", result, parse);
				if (ObjectUtil.isEmpty(parse) || StrUtil.isBlank(parse.getString("result"))) {
					return R.fail("人脸注册失败");
				}
				JSONObject token = JSONObject.parseObject(parse.getString("result"));
				user.setFaceToken(token.getString("face_token"));
				if (userService.updateById(user)) {
					return R.success("人脸注册成功");
				}
				return R.fail("人脸信息保存失败");
			}
			return R.fail("鉴权失败");
		} catch (Exception e) {
			e.printStackTrace();
			return R.fail("人脸注册失败");
		}
	}

	@ApiOperation("人脸识别")
	@RequestMapping(value = "/faceIdentify", method = RequestMethod.POST)
	public Kv faceIdentify(@RequestBody FaceIdentifyData faceIdentifyData) {
		Kv authInfo = Kv.create();
		//log.info("faceIdentify === {}",faceIdentifyData);
		if (StrUtil.isBlank(faceIdentifyData.getImage())) {
			return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", "人脸图像不能为空");
		}
		if(faceIdentifyData.getLoginType() == null){
			return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", "登录类型不能为空");
		}
		String url = "https://opapi.bol.wo.cn/aicgi/face-api/v3/face/identify";
		//String url = "https://aip.baidubce.com/rest/2.0/face/v3/multi-search";
		try {
			String accessToken = getAccessToken();
			if (!"FAIL".equals(accessToken) && StrUtil.isNotBlank(accessToken)) {
				Map<String, Object> map = new HashMap<>();
				map.put("image", faceIdentifyData.getImage());
				map.put("image_type", "BASE64");
				map.put("group_id_list", groupId);
				map.put("liveness_control", "NORMAL");
				map.put("quality_control", "LOW");

				String param =  JSON.toJSONString(map);

				Map<String, String> headers = new HashMap<>();
				headers.put("access_token", accessToken);

				String result = HttpUtils.doPostByJson(url, headers, param);

				JSONObject parse = JSONObject.parseObject(result);
				log.info("人脸识别返回结果 === result {},parse {}", result, parse);
				if (ObjectUtil.isEmpty(parse) || "222202".equals(parse.getString("error_code"))) {
					return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", "未检测到人脸");
				}
				if (ObjectUtil.isEmpty(parse) || !"0".equals(parse.getString("error_code"))) {
					return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", parse.getString("error_msg"));
				}
				String res = parse.getString("result");
				JSONObject resJson = JSONObject.parseObject(res);
				JSONObject userlist = resJson.getJSONArray("user_list").getJSONObject(0);
				Double scoresDble = new Double(userlist.getString("score"));
				if (scoresDble >= 80) {
					return faceLogin(userlist.getString("user_id"),faceIdentifyData.getLoginType());
				} else {
					return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", "人脸相似度太低，请重新录入");
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	@ApiOperation("联通人脸识别")
	@RequestMapping(value = "/unicomFaceIdentify", method = RequestMethod.POST)
	public Kv unicomFaceIdentify(@RequestBody FaceIdentifyData faceIdentifyData) {
		Kv authInfo = Kv.create();
		//log.info("faceIdentify === {}",faceIdentifyData);
		if (StrUtil.isBlank(faceIdentifyData.getImage())) {
			return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", "人脸图像不能为空");
		}
		if(faceIdentifyData.getLoginType() == null){
			return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", "登录类型不能为空");
		}
		String url = "https://opapi.bol.wo.cn/aicgi/face-api/v3/face/identify";
		//String url = "https://aip.baidubce.com/rest/2.0/face/v3/multi-search";
		try {
			String accessToken = getAccessToken();
			if (!"FAIL".equals(accessToken) && StrUtil.isNotBlank(accessToken)) {
				Map<String, Object> map = new HashMap<>();
				map.put("image", faceIdentifyData.getImage());
				map.put("image_type", "BASE64");
				map.put("group_id_list", groupId);
				map.put("liveness_control", "NORMAL");
				map.put("quality_control", "LOW");

				String param =  JSON.toJSONString(map);

				Map<String, String> headers = new HashMap<>();
				headers.put("access_token", accessToken);

				String result = HttpUtils.doPostByJson(url, headers, param);

				JSONObject parse = JSONObject.parseObject(result);
				log.info("人脸识别返回结果 === result {},parse {}", result, parse);
				if (ObjectUtil.isEmpty(parse) || "222202".equals(parse.getString("error_code"))) {
					return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", "未检测到人脸");
				}
				if (ObjectUtil.isEmpty(parse) || !"0".equals(parse.getString("error_code"))) {
					return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", parse.getString("error_msg"));
				}
				String res = parse.getString("result");
				JSONObject resJson = JSONObject.parseObject(res);
				JSONObject userlist = resJson.getJSONArray("user_list").getJSONObject(0);
				Double scoresDble = new Double(userlist.getString("score"));
				if (scoresDble >= 80) {
					User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getFaceUserId, userlist.getString("user_id")).eq(User::getIsDeleted, 0));
					if (user == null) {
						return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", "用户不存在");
					}
					if (faceIdentifyData.getLoginType() == 2 && user.getIsWxLogin() == 1) {
						return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", "该用户不能使用小程序扫脸登录");
					}
					if (StrUtil.isBlank(user.getPhone())) {
						return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", "请联系管理员填写手机号，需要双重认证");
					}
					//开始发送短信
//					String errMsg = UnicomUtil.sendSms(user.getPhone());
//					if(errMsg != null) {
//						return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", "短信发送失败|"+errMsg);
//					}
					log.info("faceLogin:success|userid={},realname={},mobile={}", user.getId(), user.getRealName(), user.getPhone());
					return authInfo.set("error_code", HttpServletResponse.SC_OK).set("mobile", DesensitizedUtil.mobilePhone(user.getPhone())).set("user_sign", UnicomUtil.encryptAes(user.getId(), user.getPhone()));
				} else {
					return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", "人脸相似度太低，请重新录入");
				}
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
		return null;
	}
	
	public Kv faceLogin(String uid,Integer loginType) {
		Kv authInfo = Kv.create();
		log.info("faceLogin === uid {}", uid);
		User user = userService.getOne(new LambdaQueryWrapper<User>()
			.eq(User::getFaceUserId, uid)
			.eq(User::getIsDeleted, 0));
		log.info("faceLogin === user {}", user);
		if (user == null) {
			return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", "用户不存在");
		}
		UserInfo userInfo = grant(user);

		if (userInfo == null || userInfo.getUser() == null) {
			return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", "用户名或密码不正确");
		}

		if (loginType == 2 && user.getIsWxLogin() == 1) {
			return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", "该用户不能使用小程序扫脸登录");
		}

		if (Func.isEmpty(userInfo.getRoles())) {
			return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", "未获得用户的角色信息");
		}

		return TokenUtil.createAuthInfo(userInfo);
	}

	public UserInfo grant(User user) {
		String tenantId = user.getTenantId();
		String username = user.getAccount();
		String password = user.getPassword();
		UserInfo userInfo = null;
		if (StrUtil.isNotBlank(username) && StrUtil.isNotBlank(password)) {
			// 获取租户信息
			Tenant tenant = tenantService.getByTenantId(tenantId);
			if (TokenUtil.judgeTenant(tenant)) {
				throw new ServiceException(TokenUtil.USER_HAS_NO_TENANT_PERMISSION);
			}
			// 根据不同用户类型调用对应的接口返回数据，用户可自行拓展
			userInfo = userService.userInfo(tenantId, username, password, UserEnum.WEB);
		}
		return userInfo;
	}


	@ApiOperation("删除人脸")
	@RequestMapping(value = "/faceRemove", method = RequestMethod.POST)
	public R faceRemove(@RequestBody FaceRemoveData faceRemoveData) {
		if (StrUtil.isBlank(faceRemoveData.getFaceGroupId()) || StrUtil.isBlank(faceRemoveData.getFaceToken()) || StrUtil.isBlank(faceRemoveData.getFaceUserId())) {
			return R.fail("缺少必要参数");
		}
		//String url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/face/delete";
		String url = "https://opapi.bol.wo.cn/aicgi/face-api/v3/face/delete";
		try {
			String accessToken = getAccessToken();
			if (!"FAIL".equals(accessToken) && StrUtil.isNotBlank(accessToken)) {
				Map<String, Object> map = new HashMap<>();
				map.put("user_id", faceRemoveData.getFaceUserId());
				map.put("group_id", faceRemoveData.getFaceGroupId());
				map.put("face_token", faceRemoveData.getFaceToken());
				String param = JSON.toJSONString(map);

				Map<String, String> headers = new HashMap<>();
				headers.put("access_token", accessToken);
				String result = HttpUtils.doPostByJson(url, headers, param);

				JSONObject parse = JSONObject.parseObject(result);
				log.info("人脸删除返回结果 === result {},parse {}", result, parse);
				if (ObjectUtil.isEmpty(parse) || !"0".equals(parse.getString("error_code"))) {
					return R.fail("error_code:" + parse.getString("error_code") + ",error_msg:" + parse.getString("error_msg"));
				} else {
					User user = userService.getOne(new LambdaQueryWrapper<User>()
						.eq(User::getFaceUserId, faceRemoveData.getFaceUserId())
						.eq(User::getFaceGroupId, faceRemoveData.getFaceGroupId())
						.eq(User::getFaceToken, faceRemoveData.getFaceToken())
						.eq(User::getIsDeleted, 0));

					userService.update(Wrappers.<User>lambdaUpdate()
						.set(User::getFaceToken, null)
						.set(User::getFaceUserId, null)
						.set(User::getFaceGroupId, null)
						.set(User::getFaceImg, null)
						.eq(User::getId, user.getId())
					);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			return R.fail("人脸删除异常");
		}
		return R.success("人脸删除成功");
	}


	@Value("${customAI.apiKey}")
	private String apiKey;

	@Value("${customAI.secretKey}")
	private String secretKey;

	@Value("${customAI.accUrl}")
	private String accUrl;


	/**
	 * 百度鉴权
	 *
	 * @return
	 */
	private String getAccessToken() {
		try {
			String accessUrl = accUrl;

			Map<String, Object> map = new HashMap<>();
			map.put("grant_type", "client_credentials");
			map.put("client_id", apiKey);
			map.put("client_secret", secretKey);

			String res = HttpUtil.createPost(accessUrl).body(JSON.toJSONString(map)).execute().body();
//			String res = HttpRequest.post(accessUrl).bodyString(JSON.toJSONString(map)).execute().asString();
			log.info("getAccessToken res = " + res);

			JSONObject parse = JSONObject.parseObject(res);
			if (ObjectUtil.isEmpty(parse)) {
				return "FAIL";
			}
			return parse.getString("access_token");
		} catch (Exception e) {
			e.printStackTrace();
			return "";
		}
	}


}

