package org.springblade.wecom.controller;


import cn.hutool.core.net.url.UrlQuery;
import cn.hutool.core.util.URLUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springblade.common.utils.DigestUtil;
import org.springblade.core.constant.TokenConstant;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.support.Kv;
import org.springblade.modules.auth.enums.UserEnum;
import org.springblade.modules.auth.utils.TokenUtil;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.entity.UserInfo;
import org.springblade.modules.system.entity.VisualSubscribeNotifyConf;
import org.springblade.modules.system.enums.NotifyType;
import org.springblade.modules.system.service.impl.UserServiceImpl;
import org.springblade.modules.system.service.impl.VisualSubscribeNotifyConfService;
import org.springblade.system.client.model.VisualSubscribeNotifyConfModel;
import org.springblade.wecom.entity.BladeDept;
import org.springblade.wecom.entity.BladeUser;
import org.springblade.wecom.entity.BladeUserDept;
import org.springblade.wecom.service.IBladeDeptService;
import org.springblade.wecom.service.IBladeUserDeptService;
import org.springblade.wecom.service.IBladeUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/wecom")
@Api(value = "企业微信", tags = "企业微信")
@Slf4j
public class WeComController {


	//获取AccessToken地址
	private final static String GET_ACCESS_TOKEN_URL = "cgi-bin/gettoken";
	//获取部门列表地址
	private final static String GET_DEPARTMENT_LIST_URL = "cgi-bin/department/list";
	//获取部门人员详情地址
	private final static String GET_USER_LIST_URL = "cgi-bin/user/list";

	//生成授权地址 两个环境地址相同
	private final static String OAUTH2_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?";
	//private final static String OAUTH2_URL = "https://qw.cscec8b.com.cn/connect/oauth2/authorize?";

	@Autowired
	private IBladeDeptService bladeDeptService;

	@Autowired
	private IBladeUserService bladeUserService;

	@Autowired
	private IBladeUserDeptService bladeUserDeptService;

	@Autowired
	private UserServiceImpl userServiceImpl;

	@Autowired
	private VisualSubscribeNotifyConfService notifyConfService;

	@Value("${weCom.domainName}")
	private String domainName;

	//获取访问用户身份（code） 两个环境地址不同
	@Value("${weCom.userinfoUrl}")
	private String userinfoUrl;

	@Value("${weCom.corpId}")
	private String corpId;

	@Value("${weCom.corpSecret}")
	private String corpSecret;

	@Value("${weCom.loginCorpSecret}")
	private String loginCorpSecret;

	@Value("${weCom.redirectUrl}")
	private String redirectUrl;

	@Value("${cscec8b.enabled:false}")
	private Boolean cscec8b;



	@GetMapping("/codeToToken")
	@ApiOperation(value = "PC企业微信登录code换取token")
	public Kv codeToToken(String code, String state) throws Exception {
		String accessToken = getLoginAccessToken();
		System.out.println("企业微信 codeToToken = " + code + "===============" + state);
		UserInfo userInfo = new UserInfo();
		Map<String, Object> formMap = new HashMap<>();
		formMap.put("access_token", accessToken);
		formMap.put("code", code);
		System.out.println("获取用户信息地址 userinfoUrl = " + userinfoUrl);
		String res = HttpUtil.createGet(userinfoUrl).form(formMap).execute().body();
		JSONObject jsonObject = JSONObject.parseObject(res);
		SimpleDateFormat simple = new SimpleDateFormat("yyyy-MM-dd");
		String format = simple.format(new Date());
		System.out.println("pc res jsonObject = " + jsonObject + "time = " + format);
		if (Objects.nonNull(jsonObject.get("errcode")) && jsonObject.getInteger("errcode") == 0) {
			String userid = "";
			if(domainName.contains("weixin")){
				userid = jsonObject.getString("userid");
			}
			if(domainName.contains("cscec8b")){
				userid = jsonObject.getString("UserId");
			}
			System.out.println("pc res userid = " + userid + "time = " + format);
			BladeUser bladeUser = bladeUserService.getOne(new LambdaQueryWrapper<BladeUser>()
					.eq(BladeUser::getThirdUserId, userid)
					.eq(BladeUser::getIsDeleted, 0)
			);
			System.out.println("pc res bladeUser = " + bladeUser + "time = " + format);
			User user = new User();
			BeanUtils.copyProperties(bladeUser,user);
			userInfo = userServiceImpl.userInfo(user, UserEnum.WEB);
			System.out.println("userInfo = " + userInfo);
			//userInfo.setUser(user);
		}
		Kv authInfo = TokenUtil.createAuthInfo(userInfo);
		System.out.println("authInfo = " + authInfo);
		return authInfo;
	}


	/**
	 * 获取AccessToken
	 * @return
	 * @throws Exception
	 */
	private String getAccessToken() throws Exception {
		Map<String, Object> formMap = new HashMap<>();
		formMap.put("corpid", corpId);
		formMap.put("corpsecret", corpSecret);
		String res = HttpUtil.createGet(domainName+GET_ACCESS_TOKEN_URL).form(formMap).execute().body();
		JSONObject jsonObject = JSONObject.parseObject(res);
		if (Objects.nonNull(jsonObject.get("errcode")) && jsonObject.getInteger("errcode") == 0) {
			return jsonObject.getString("access_token");
		}
		throw new RuntimeException("企业微信|获取accessToken失败|res=" + res);
	}

	/**
	 * 企业微信登录获取AccessToken（八局需单独获取）
	 * @return
	 * @throws Exception
	 */
	private String getLoginAccessToken() throws Exception {
		Map<String, Object> formMap = new HashMap<>();
		formMap.put("corpid", corpId);
		formMap.put("corpsecret", loginCorpSecret);
		String res = HttpUtil.createGet(domainName+GET_ACCESS_TOKEN_URL).form(formMap).execute().body();
		JSONObject jsonObject = JSONObject.parseObject(res);
		if (Objects.nonNull(jsonObject.get("errcode")) && jsonObject.getInteger("errcode") == 0) {
			return jsonObject.getString("access_token");
		}
		throw new RuntimeException("企业微信|获取accessToken失败|res=" + res);
	}


	/**
	 * 获取部门信息
	 * @param accessToken
	 * @return
	 */
	private JSONArray getDepartmentList(String accessToken,Integer id,Integer child)  {
		Map<String, Object> formMap = new HashMap<>();
		formMap.put("access_token", accessToken);
		formMap.put("id", id);
		formMap.put("no_fetch_child", child);// 0 递归 1 不递归
		String res = HttpUtil.createGet(domainName + GET_DEPARTMENT_LIST_URL).form(formMap).execute().body();
		JSONObject jsonObject = JSONObject.parseObject(res);
		if (Objects.nonNull(jsonObject.get("errcode")) && jsonObject.getInteger("errcode") == 0) {
			return jsonObject.getJSONArray("department");
		}
		throw new RuntimeException("企业微信|获取部门信息列表失败|res=" + res);
	}

	private JSONArray getDepartmentList(String accessToken)  {
		return getDepartmentList(accessToken,null,null);
	}

	/**
	 * 获取部门人员详情
	 * @param accessToken
	 * @return
	 */
	private JSONArray getUserList(String accessToken,Long departmentId)  {
		Map<String, Object> formMap = new HashMap<>();
		formMap.put("access_token", accessToken);
		formMap.put("department_id", departmentId);
		formMap.put("no_fetch_child", 0);
		String res = HttpUtil.createGet(domainName + GET_USER_LIST_URL).form(formMap).execute().body();
		JSONObject jsonObject = JSONObject.parseObject(res);
		if (Objects.nonNull(jsonObject.get("errcode")) && jsonObject.getInteger("errcode") == 0) {
			return jsonObject.getJSONArray("userlist");
		}
		throw new RuntimeException("企业微信|获取部门人员详情失败|res=" + res);
	}


	@GetMapping("/dataSys")
	@ApiOperation(value = "企业微信通讯录同步（新逻辑）")
	public R dataSys(String tenantId,String roleId) throws Exception {
		if(StringUtils.isBlank(tenantId)){
			return R.fail("租户ID不能为空");
		}
		if(StringUtils.isBlank(roleId)){
			return R.fail("角色ID不能为空");
		}
		String accessToken = getAccessToken();
		//获取根部门
		JSONArray departmentList = getDepartmentList(accessToken,1,1);
		if(departmentList.isEmpty()){
			return R.fail("根部门数据为空");
		}
		log.info("根部门数量 - size = {}",departmentList.size());
		for (int i = 0; i < departmentList.size(); i++) {
			JSONObject jsonObject = departmentList.getJSONObject(i);
			Long id = jsonObject.getLong("id");
			if(id==1L){
				log.info("id ======= {}",id);
				BladeDept dept = bladeDeptService.getById(id);
				if(dept != null){
					continue;
				}else {
					String name = jsonObject.getString("name");
					Long parentid = jsonObject.getLong("parentid");
					Integer order = jsonObject.getInteger("order");
					BladeDept bladeDept = new BladeDept();
					bladeDept.setId(id);
					bladeDept.setDeptCategory(1);
					bladeDept.setDeptName(name);
					bladeDept.setFullName(name);
					bladeDept.setParentId(parentid);
					bladeDept.setSort(order);
					bladeDept.setTenantId(tenantId);
					bladeDeptService.save(bladeDept);
				}
			}
		}

		//获取指定部门及子部门
		JSONArray departList = null;
		if(domainName.contains("weixin")){
			departList = getDepartmentList(accessToken);
		}
		if(domainName.contains("cscec8b")){
			departList = getDepartmentList(accessToken,1204,0);
		}
		if(departList.isEmpty()){
			return R.fail("指定部门数据为空");
		}
		log.info("指定部门数量 - size = {}",departList.size());
		for (int i = 0; i < departList.size(); i++) {
			JSONObject jsonObject = departList.getJSONObject(i);
			Long id = jsonObject.getLong("id");
			BladeDept dept = bladeDeptService.getById(id);
			if(dept != null){
				JSONArray userList = getUserList(accessToken, id);
				log.info("userList-size = {}",userList.size());
				if(userList.size() == 0){
					log.info("userList is null department_id = {}",id);
					continue;
				}
				List<BladeUser> list = bladeUserService.list(new LambdaQueryWrapper<BladeUser>()
						.eq(BladeUser::getDeptId, dept.getId())
				);
				List<String> nStrings = new ArrayList<>();
				for (int j = 0; j < userList.size(); j++) {
					JSONObject userObject = userList.getJSONObject(j);
					nStrings.add(userObject.getString("userid"));
				}
				List<String> collect = new ArrayList<>();
				if(list.size() > 0){
					collect = list.stream()
							.map(BladeUser::getThirdUserId)
							.collect(Collectors.toList());
				}
				nStrings.removeAll(collect);
				//循环差集多出来的人，有没有之前就已经在数据库存在的（调岗逻辑）
				List<String> tgStrings = new ArrayList<>();
				for (String nString : nStrings) {
					List<BladeUser> tgList = bladeUserService.list(new LambdaQueryWrapper<BladeUser>()
							.eq(BladeUser::getThirdUserId, nString)
					);
					if(tgList.size()>0){
						for (BladeUser bladeUser : tgList) {
							bladeUser.setDeptId(dept.getId().toString());
						}
						bladeUserService.updateBatchById(tgList);
						tgStrings.add(nString);
					}
				}
				nStrings.removeAll(tgStrings);
				List<BladeUser> batchList = new ArrayList<>();
				for (int j1 = 0; j1 < userList.size(); j1++) {
					JSONObject userObject = userList.getJSONObject(j1);
					String userid = userObject.getString("userid");
					if(nStrings.contains(userid)){
						log.info("差集包含未同步人员，补齐人员信息到数据源 ={}",userid);
						String userName = userObject.getString("name");
						String mobile = userObject.getString("mobile");
						String email = userObject.getString("email");
						//性别。0表示未定义，1表示男性，2表示女性
						Integer gender = userObject.getInteger("gender");
						BladeUser bladeUser = new BladeUser();
						if(domainName.contains("weixin")){
							bladeUser.setAccount(userid);
						}
						if(domainName.contains("cscec8b")){
							bladeUser.setAccount(mobile);
						}
						bladeUser.setThirdUserId(userid);
						bladeUser.setName(userName);
						bladeUser.setIsLogin(0);
						bladeUser.setIsWxLogin(0);
						bladeUser.setLoginStatus(0);
						bladeUser.setRealName(userName);
						bladeUser.setPhone(mobile);
						bladeUser.setEmail(email);
						bladeUser.setUserAttr(0);
						bladeUser.setSex(gender);
						bladeUser.setDeptId(id.toString());
						bladeUser.setCreateTime(new Date());
						bladeUser.setUpdateTime(new Date());
						bladeUser.setPassword(DigestUtil.encrypt("zjbj@2024"));
						bladeUser.setTenantId(tenantId);
						bladeUser.setRoleId(roleId);
						batchList.add(bladeUser);
					}
				}
				bladeUserService.saveBatch(batchList);
			}
			else
			{
				String name = jsonObject.getString("name");
				Long parentid = jsonObject.getLong("parentid");
				Integer order = jsonObject.getInteger("order");
				BladeDept bladeDept = new BladeDept();
				bladeDept.setId(id);
				bladeDept.setDeptCategory(1);
				bladeDept.setDeptName(name);
				bladeDept.setFullName(name);
				bladeDept.setParentId(parentid);
				bladeDept.setSort(order);
				bladeDept.setTenantId(tenantId);
				boolean res = bladeDeptService.save(bladeDept);
				if(id == 1){
					continue;
				}
				if(res){
					JSONArray userList = getUserList(accessToken, id);
					log.info("userList-size = {}",userList.size());
					if(userList.size() == 0){
						log.info("department_id = {}",id);
						continue;
					}
					List<BladeUser> batchList = new ArrayList<>();
					for (int i1 = 0; i1 < userList.size(); i1++) {
						JSONObject userObject = userList.getJSONObject(i1);
						String userName = userObject.getString("name");
						String userid = userObject.getString("userid");
						String mobile = userObject.getString("mobile");
						String email = userObject.getString("email");
						//性别。0表示未定义，1表示男性，2表示女性
						Integer gender = userObject.getInteger("gender");

						BladeUser bladeUser = new BladeUser();
						if(domainName.contains("weixin")){
							bladeUser.setAccount(userid);
						}
						if(domainName.contains("cscec8b")){
							bladeUser.setAccount(mobile);
						}
						bladeUser.setThirdUserId(userid);
						bladeUser.setIsLogin(0);
						bladeUser.setIsWxLogin(0);
						bladeUser.setLoginStatus(0);
						bladeUser.setName(userName);
						bladeUser.setRealName(userName);
						bladeUser.setPhone(mobile);
						bladeUser.setEmail(email);
						bladeUser.setUserAttr(0);
						bladeUser.setSex(gender);
						bladeUser.setDeptId(id.toString());
						bladeUser.setCreateTime(new Date());
						bladeUser.setUpdateTime(new Date());
						bladeUser.setPassword(DigestUtil.encrypt("zjbj@2024"));
						bladeUser.setTenantId(tenantId);
						bladeUser.setRoleId(roleId);
						batchList.add(bladeUser);
					}
					bladeUserService.saveBatch(batchList);

				}
			}
			List<BladeUser> saveList = bladeUserService.list(new LambdaQueryWrapper<BladeUser>()
					.eq(BladeUser::getDeptId, id)
			);
			List<BladeUserDept> userDepts = new ArrayList<>();
			if(saveList.size() > 0){
				for (BladeUser bladeUser : saveList) {
					List<BladeUserDept> depts = bladeUserDeptService.list(new LambdaQueryWrapper<BladeUserDept>()
							.eq(BladeUserDept::getUserId, bladeUser.getId())
							.eq(BladeUserDept::getDeptId, id)
					);
					if(depts.size() == 0){
						continue;
					}else {
						BladeUserDept bladeUserDept = new BladeUserDept();
						bladeUserDept.setUserId(bladeUser.getId());
						bladeUserDept.setDeptId(id);
						userDepts.add(bladeUserDept);
					}
				}
			}
			if(userDepts.size() > 0){
				bladeUserDeptService.saveBatch(userDepts);
			}
		}
		log.info("=============同步结束==============");
		return R.success("同步成功");
	}

	/**
	 * 生成授权连接
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	@GetMapping("/createOauth2Url")
	@ApiOperation(value = "生成授权连接")
	public String createOauth2Url(String redirectUri,String agentid) throws UnsupportedEncodingException {
		String encode = URLEncoder.encode(redirectUrl,"UTF-8");
		String response_type = "code";
		//静默授权
		String scope = "snsapi_base";
		//String scope = "snsapi_privateinfo";
		//String agentid = "1000006";
		String urlStr = OAUTH2_URL+ "appid=" +corpId +"&redirect_uri=" + encode  +"&response_type=" + response_type  +"&scope=" + scope  +"&state=" + redirectUri +"&agentid=" + agentid +"#wechat_redirect";
		System.out.println("urlStr = " + urlStr);
		return urlStr;
	}

	@GetMapping("/getCode")
	public void getCode(String code, String state, HttpServletResponse response) throws Exception {
		log.info("createTokenByCode = " + code + "===============" + state);
		String replaceUrl = state.replaceAll("&amp;", "&");
		String tenantId = (String) UrlQuery.of(replaceUrl, Charset.defaultCharset()).get("tenantId");
		if (StringUtils.isBlank(tenantId)) {
			throw new RuntimeException("state所在的url没有传递tenantId");
		}
		List<VisualSubscribeNotifyConf> confs = notifyConfService.newNotifyConfList(tenantId, NotifyType.qywechat);
		Map<String, String> confMap = confs.stream().collect(Collectors.toMap(VisualSubscribeNotifyConf::getAttriKey, VisualSubscribeNotifyConf::getAttriValue));
		log.info("confMap={}",confMap);
		//域名
		String corpDomain = confMap.get("corp_domain");
		String corpId = confMap.get("corp_id");
		String appSecret = confMap.get("app_secret");
		String accessToken = "";
		Map<String, Object> map = new HashMap<>();
		map.put("corpid", corpId);
		map.put("corpsecret", appSecret);
		String res = HttpUtil.createGet(URLUtil.completeUrl(corpDomain, GET_ACCESS_TOKEN_URL)).form(map).execute().body();
		log.info("res:"+res);
		JSONObject result = JSONObject.parseObject(res);
		if (Objects.nonNull(result.get("errcode")) && result.getInteger("errcode") == 0) {
			accessToken= result.getString("access_token");
		}
		UserInfo userInfo = new UserInfo();
		Map<String, Object> formMap = new HashMap<>();
		formMap.put("access_token", accessToken);
		formMap.put("code", code);
		String body ="";
		if (cscec8b){
			body = HttpUtil.createGet(URLUtil.completeUrl(corpDomain, "/cgi-bin/user/getuserinfo")).form(formMap).execute().body();
		}else {
			 body = HttpUtil.createGet(URLUtil.completeUrl(corpDomain, "/cgi-bin/auth/getuserinfo")).form(formMap).execute().body();
		}
		log.info("body:"+body);
		JSONObject jsonObject = JSONObject.parseObject(body);
		SimpleDateFormat simple = new SimpleDateFormat("yyyy-MM-dd");
		String format = simple.format(new Date());
		log.info("qywx res jsonObject = " + jsonObject + "time = " + format);
		if (Objects.nonNull(jsonObject.get("errcode")) && jsonObject.getInteger("errcode") == 0) {
			String userid = jsonObject.getString("userid");
			log.info("qywx userid  = " + userid + "time = " + format);
			BladeUser bladeUser = bladeUserService.getOne(new LambdaQueryWrapper<BladeUser>()
					.eq(BladeUser::getThirdUserId, userid)
					.eq(BladeUser::getIsDeleted, 0)
			);
			log.info("qywx bladeUser  = " + bladeUser + "time = " + format);
			User user = new User();
			BeanUtils.copyProperties(bladeUser,user);
			userInfo.setUser(user);
		}
		String resUrl = replaceUrl+"&token="+TokenUtil.createAuthInfo(userInfo).getStr("access_token");
		//String resUrl = replaceUrl+"&token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJpc3N1c2VyIiwiYXVkIjoiYXVkaWVuY2UiLCJ0ZW5hbnRfaWQiOiJveWU3ZDNvIiwidXNlcl9uYW1lIjoiMTM4MTIzNDU2NzgiLCJtb2JpbGUiOiIxMzgxMjM0NTY3OCIsInRva2VuX3R5cGUiOiJhY2Nlc3NfdG9rZW4iLCJyb2xlX25hbWUiOiJhZG1pbiIsInBvc3RfaWQiOiIxNzgyNzAwMjA2MjIzMDg5NjY1IiwidXNlcl9pZCI6IjE3ODI3MDAyMDcxODM1ODUyODEiLCJyb2xlX2lkIjoiMTc4MjcwMDIwNjE4OTUzNTIzMyIsIm5pY2tfbmFtZSI6IueuoeeQhuWRmCIsImRldGFpbCI6eyJ0eXBlIjoid2ViIiwidXNlckZsYWciOjEsInRoaXJkVXNlcklkIjpudWxsLCJ0aGlyZERlcHRJZCI6Im51bGwiLCJ0aGlyZFBvc3RJZCI6ImNlbyJ9LCJkZXB0X2lkIjoiMTc4MjcwMDIwNjIwNjMxMjQ1MCIsImFjY291bnQiOiIxMzgxMjM0NTY3OCIsImNsaWVudF9pZCI6InNhYmVyIiwiZXhwIjoxNzIwMDMzMzQ5LCJuYmYiOjE3MTk5OTczNDl9.whKTd1MQRWl_jRrB_sUwpRR9T9ujGJcgFGzzCCqvRBCYxnK3Q2cm3PNfKY6i5rHDWnAFp_457nldAWRZScVMxw";
		log.info("authInfo = " + resUrl);
		response.sendRedirect(resUrl);
	}

}

