package cn.myapps.runtime.login.controller;

import com.bcxin.components.CacheConst;
import cn.myapps.authtime.common.service.AuthTimeServiceManager;
import cn.myapps.authtime.domain.dao.DomainDAO;
import cn.myapps.authtime.domain.model.DomainVO;
import cn.myapps.authtime.domain.service.DomainProcess;
import cn.myapps.authtime.user.model.BaseUser;
import cn.myapps.authtime.user.model.UserVO;
import cn.myapps.authtime.user.service.UserProcess;
import cn.myapps.base.web.WebUser;
import cn.myapps.common.Environment;
import cn.myapps.common.ModelSuffix;
import cn.myapps.common.model.application.Application;
import cn.myapps.common.model.permission.Permission;
import cn.myapps.common.model.resource.ResourceVO;
import cn.myapps.common.model.role.Role;
import cn.myapps.common.model.sysconfig.AuthConfig;
import cn.myapps.common.util.*;
import cn.myapps.conf.LoginConfig;
import cn.myapps.constans.Web;
import cn.myapps.designtime.application.service.ApplicationDesignTimeService;
import cn.myapps.designtime.common.service.DesignTimeServiceManager;
import cn.myapps.designtime.permission.PermissionUtil;
import cn.myapps.designtime.resource.service.ResourceDesignTimeService;
import cn.myapps.designtime.role.service.RoleDesignTimeService;
import cn.myapps.runtime.common.dao.DAOFactory;
import cn.myapps.runtime.logger.service.LogHelper;
import cn.myapps.support.dingding.service.DdApiService;
import cn.myapps.util.http.CookieUtil;
import cn.myapps.util.property.MultiLanguageProperty;
import cn.myapps.util.sequence.Sequence;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bcxin.runtime.apis.controllers.ControllerAbstract;
import com.bcxin.saas.core.components.DistributedCacheProvider;
import com.bcxin.saas.core.utils.encrypt.PasswordUtils;
import com.bcxin.saas.domains.dtos.AjaxResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

@RestController
@Api(tags = "登录模块")
public class LoginController extends ControllerAbstract {

//    @Autowired
//    private AuthenticationManager authenticationManager;

	@Autowired
	private HttpServletRequest request;

	@Autowired
	private HttpServletResponse response;

	@GetMapping(value = "/")
	@ApiOperation(value = "访问主页面", notes = "访问主页面")
	public void doIndexPage() throws Exception {
		String skin = PropertyUtil.get("useSkin");
		String url = "signon/dispatcher.html?skin="+skin;
		response.sendRedirect(url);
	}

	@GetMapping(value = "/api/login")
	@ApiOperation(value = "访问登录页面", notes = "访问登录页面")
	public void doLoginPage() throws Exception {
		String url = "signon/login.html";
		response.sendRedirect(url);
	}

	/**
	 * restful登陆接口 获取登陆页面所需的多语言字段
	 *
	 * @param jsonObj
	 * @param request
	 * @return
	 */
	@ResponseBody
	@PostMapping(path = "/api/runtime/login/getMultiLangWordList")
	@ApiOperation(value = "获取登陆页面所需的多语言字段", notes = "获取登陆页面所需的多语言字段")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "jsonObj",value = "请求包体",required = true,paramType = "body",dataType = "string")
	})
	public JSON getMultiLangWordList(@RequestBody JSONObject jsonObj, HttpServletRequest request) {
		Map MultiLangWordMap;
		String language = jsonObj.getString("language");
		try {
			MultiLangWordMap = getLoginMultiLangWordList(language);

			Cookie cookie = new Cookie(Web.SESSION_ATTRIBUTE_USERLANGUAGE, language);
			cookie.setPath("/");
			cookie.setMaxAge(7200);
			response.addCookie(cookie);

			return result("1", "成功", "multiLangWordList", MultiLangWordMap, null, null);
		} catch (Exception e) {
			return result("0", "失败", "multiLangWordList", null, null, null);
		}
	}

	/**
	 * 获取登陆多语言字段的方法
	 *
	 * @param language
	 * @return
	 * @throws Exception
	 */
	private Map getLoginMultiLangWordList(String language) throws Exception {
		Map MultiLangWordMap = new HashMap();
		String domains = MultiLanguageProperty.getProperty(language, "Domains", "");
		String pageLoginAccount = MultiLanguageProperty.getProperty(language, "page.login.account", "");
		String pageLoginPassword = MultiLanguageProperty.getProperty(language, "page.login.password", "");
		String pageLoginRememberLabel = MultiLanguageProperty.getProperty(language, "page.login.remember.label", "");
		String debug = MultiLanguageProperty.getProperty(language, "Debug", "");
		String login = MultiLanguageProperty.getProperty(language, "Login", "");
		String frontPageLoginCopyRight = MultiLanguageProperty.getProperty(language, "front.page.login.copyright", "");
		String smsCode = MultiLanguageProperty.getProperty(language, "page.function.info.sms.code", "");
		String userNoExist = MultiLanguageProperty.getProperty(language, "core.user.notexist", "");
		String imgCode = MultiLanguageProperty.getProperty(language, "page.login.img.code", "");
		String scanCode = MultiLanguageProperty.getProperty(language, "page.login.scan.code", "");
		String appScan = MultiLanguageProperty.getProperty(language, "page.login.app.scan", "");
		String wechatLogin = MultiLanguageProperty.getProperty(language, "page.login.wechat", "");
		String wechatScan = MultiLanguageProperty.getProperty(language, "page.login.wechat.scan", "");
		String dingdingLogin = MultiLanguageProperty.getProperty(language, "page.login.dingding", "");
		String dingdingScan = MultiLanguageProperty.getProperty(language, "page.login.dingding.scan", "");

		MultiLangWordMap.put("domains", domains);
		MultiLangWordMap.put("pageLoginAccount", pageLoginAccount);
		MultiLangWordMap.put("pageLoginPassword", pageLoginPassword);
		MultiLangWordMap.put("pageLoginRememberLabel", pageLoginRememberLabel);
		MultiLangWordMap.put("login", login);
		MultiLangWordMap.put("frontPageLoginCopyright", frontPageLoginCopyRight);
		MultiLangWordMap.put("smsCode", smsCode);
		MultiLangWordMap.put("userNoExist", userNoExist);
		MultiLangWordMap.put("imgCode", imgCode);
		MultiLangWordMap.put("scanCode", scanCode);
		MultiLangWordMap.put("appScan", appScan);
		MultiLangWordMap.put("wechatLogin", wechatLogin);
		MultiLangWordMap.put("wechatScan", wechatScan);
		MultiLangWordMap.put("dingdingLogin", dingdingLogin);
		MultiLangWordMap.put("dingdingScan", dingdingScan);
		return MultiLangWordMap;
	}

	/**
	 * restful登陆接口 改变验证码
	 *
	 * @return
	 * @throws Exception
	 */
	@ResponseBody
	@PostMapping(path = "/api/runtime/login/changeCheckcodeImg")
	@ApiOperation(value = "改变验证码", notes = "改变验证码")
	public JSON changeCheckcodeImg() throws Exception {
		String png_base64 = getCheckCodeImg();
		return result("1", "改变成功", "checkcode", "data:image/jpg;base64," + png_base64, null, null);
	}

	/**
	 * restful登陆接口 获取企业域列表
	 *
	 * @return
	 */
	@ResponseBody
	@PostMapping(path = "/api/runtime/login/getDomainList")
	@ApiOperation(value = "获取企业域列表", notes = "获取企业域列表")
	public JSON getDomainList() throws Exception {
		try {
			Map<String,Object> hashMap = getAuthConfig();
			String path = PropertyUtil.getByPropName("sso", AuthConfig.Login_Background);
			ArrayList arr = new ArrayList<>();
			arr.add("xxxxxx1");
			hashMap.put("domainList",arr);
			
			hashMap.put("loginBackground",path);
			return result("1", "成功", "result", hashMap, null, null);
		} catch (Exception e) {
			return result("0", "失败", "result", null, null, null);
		}
	}

	private Map<String, Object> getAuthConfig() {
		Map<String, Object> configMap = new HashMap<>();
		String freeTemplate = LoginConfig.getHomeTemplateBoradType();
		if(StringUtil.isBlank(freeTemplate)) {
			freeTemplate = "";
		}

		configMap.put("homeTemplateBoradType", freeTemplate);

		Properties props = new Properties();
		InputStream stream = null;
		String realpath = PropertyUtil.getPath();
		URL propsUrl = null;
		try {
			propsUrl = new URL("file", null, realpath + "/" + "sso.properties");
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		if (propsUrl == null) {
			throw new IllegalStateException("sso.properties missing");
		}
		try {
			stream = propsUrl.openStream();
			props.load(new InputStreamReader(stream, "UTF-8"));
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (stream != null) {
				try {
					stream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				stream = null;
			}
		}
		configMap.put("loginBackground", props.getProperty(AuthConfig.Login_Background));
		configMap.put("loginLogo", props.getProperty(AuthConfig.Login_Logo));
		configMap.put("loginTitle", props.getProperty(AuthConfig.Login_Title));
		configMap.put("isRegister", props.getProperty(AuthConfig.Login_IsRegister));
		configMap.put("registerTitle", props.getProperty(AuthConfig.Register_Title));
		configMap.put("registerUrl", props.getProperty(AuthConfig.Register_Url));
		configMap.put("isSupervise", props.getProperty(AuthConfig.Site_IsSupervise));
		configMap.put("areaCode", props.getProperty(AuthConfig.areaCode));

		return configMap;
	}

	@ResponseBody
	@PostMapping("/api/runtime/login/loginWithCiphertext2")
	@ApiOperation(value = "登录", notes = "登录")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "jsonObj",value = "请求包体",required = true,paramType = "body",dataType = "string")
	})
	public JSON login(@RequestBody JSONObject jsonObj) throws Exception {
		String domainName = jsonObj.getString("domainName");
		String username = jsonObj.getString("username");
		String password = jsonObj.getString("password");
//        String password = "IzNDU2MT";
		String remember = jsonObj.getString("remember");
		String checkcode = jsonObj.getString("checkcode");
		String language = jsonObj.getString("language");
		String debug = jsonObj.getString("debug");

		if (domainName == null) {
//            String coreDomainLabelNameIllegal = MultiLanguageProperty.getProperty(language, "cn.myapps.core.domain.label.name.illegal", "");
			return result("0", "{*[cn.myapps.core.domain.label.name.illegal]*}", "returnUrl", "", "checkcodeImg", "");
		}

		DomainDAO domainDAO = (DomainDAO) DAOFactory.getDefaultDAO(DomainVO.class.getName());
		final DomainVO domain = domainDAO.getDomainByName(domainName);
		if (domain == null || domain.getStatus() == 0) {
//            String coreDomainNotexist = MultiLanguageProperty.getProperty(language, "core.domain.notexist", "");
			return result("0", "{*[core.domain.notexist]*}", "returnUrl", "", "checkcodeImg", "");
		}

		Integer count = 0;
//		User user = userRepository.findByUsernameAndDomain(username, domainName);
		UserProcess up = AuthTimeServiceManager.userRuntimeService();
		UserVO user = up.getUserByLoginnoAndDoaminName(username, domainName);
		if (user == null) {
			return result("0", "{*[core.user.notexist]*}", "returnUrl", "", "checkcodeImg", "");
		}
		count = user.getPwdErrorTimes();

		String png_base64 = "";

		if (count > 2) {
			String code = (String) request.getSession().getAttribute(CheckCode_Session);
			if (code != null && !code.equalsIgnoreCase(checkcode)) {
//                String coreSecurityCharacterError = MultiLanguageProperty.getProperty(language, "core.security.character.error", "");
				png_base64 = "data:image/jpg;base64," + getCheckCodeImg();
				return result("0", "输入字符错误，请重新输入图片中出现的4个字符", "returnUrl", "", "checkcodeImg", png_base64);
			}
		}

		if (count >= 2) {
			png_base64 = "data:image/jpg;base64," + getCheckCodeImg();
		}

		if (user != null && user.getLockFlag() == 0) {
//            String LockedAccount = MultiLanguageProperty.getProperty(language, "LockedAccount", "");
			return result("0", "该账号已锁定", "returnUrl", "", "checkcodeImg", png_base64);
		}

		if (user != null) {
			String author = PropertyUtil.get("ao.login.notice.author");
			if("0".equals(author)){
				String maxAge = PropertyUtil.get("ao.login.password.maxage");
				if(maxAge != null){
					long overdueTime = Integer.valueOf(maxAge)*24*60*60*1000;
					long oldTime = user.getLastModifyTime().getTime();
					long nowTime = new Date().getTime();
					if(nowTime - oldTime > overdueTime){
						return result("0", "密码已过期", "returnUrl", "", "checkcodeImg", png_base64);
					}
				}
			}
		}

		// 密码解密
		if (password != null && password.length() > 2) {
			String lp = password.substring(0, password.length() - 2);
			String rp = password.substring(password.length() - 2, password.length());
			password = Security.decodeBASE64(rp + lp);

		}

		String token = null;
		try {
			up.login(user.getLoginno(),password,user.getDomain().getName(),count);

			String encodedPassword = user.getLoginpwd();
			if(PasswordUtils.isMatched(encodedPassword,password)){
				token = Security.getToken(user.getId());
				// 存放到cookie
				Cookie cookie = new Cookie(Security.ACCESS_TOKEN, token);
				Cookie isFromLogin = new Cookie("isFromLogin","1");
//				cookie.setHttpOnly(true);//调试方便，先注释
				cookie.setPath("/");
				cookie.setMaxAge(7200);
				isFromLogin.setPath("/");
				response.addCookie(cookie);
				response.addCookie(isFromLogin);
			} else {
				throw new Exception("登陆错误!");
			}

//            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username+"@"+domainName, password);
//            Authentication authentication = authenticationManager.authenticate(token);
//            SecurityContextHolder.getContext().setAuthentication(authentication);
//
//            request.getSession().setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());

			if (this.isAgent(user)) {
				return result("1", "代理登陆页面", "returnUrl", "../login/agent.html?id="+user.getId(), Security.ACCESS_TOKEN, token);
			}

		} catch (Exception e) {
			up.updateUserPwdErrorTimes(username, count + 1);
			return result("0",e.getMessage(),"returnUrl","","checkcodeImg", png_base64);
		}

//		if (remember.equals("0") ? false : true) {
//			CookieAuthValidator cookieAuthValidator = new CookieAuthValidator();
//			cookieAuthValidator.addCookie(user, response);
//		}

//        WebCookies webCookies = getWebCooikes();
//        webCookies.addCookie("_dn", domainName);
//        webCookies.addCookie("_ac", username);

//        request.setAttribute("application", user.getApplicationid());
//		up.updateUserLockFlag(username, 0);

//        DomainVO domain = (DomainVO) domainProcess.doView(getUser().getDomainid());
//        if (domain.getLog()) {
//            LogProcess logProcess = (LogProcess) ProcessFactory.createProcess(LogProcess.class);
//            String ip = LogHelper.getRequestIp(request);
//            LogVO log = LogVO.valueOf(getUser(), "{*[Login]*}", "{*[Login]*}{*[System]*}", ip);
//            logProcess.doCreate(log);
//        }
		//每次登录后重新更新缓存
		WebUser webUser = new WebUser(user);
		WebUser.setWebUser(webUser, request);
		//记录日志
		LogHelper.saveLogByDyAction("登录", "登录", webUser, request);

		try{
			//license过期校验
			DomainProcess process = AuthTimeServiceManager.domainRuntimeService();
			process.doUpdate(domain);
		} catch(Exception e){
		}

		String skin = PropertyUtil.getByPropName("skin", "homePage");
		return result("1", "登陆成功", "returnUrl", "../signon/dispatcher.html?skin="+skin, "checkcodeImg", "", Security.ACCESS_TOKEN, token);
	}

	/**
	 * 钉钉免登
	 * @param code 免登授权码
	 * @param domainId 企业域id
	 * @param appId 软件id
	 * @throws Exception
	 */
	@ResponseBody
	@GetMapping(path = "/api/runtime/dingding/authlogin")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "code",value = "钉钉免登授权码",required = true,paramType = "query",dataType = "string"),
			@ApiImplicitParam(name = "domainId",value = "企业域id",required = true,paramType = "query",dataType = "string"),
			@ApiImplicitParam(name = "appId",value = "软件id",required = false,paramType = "query",dataType = "string"),
			@ApiImplicitParam(name = "formId",value = "表单id",required = false,paramType = "query",dataType = "string"),
			@ApiImplicitParam(name = "isPc",value = "是否来自pc",required = false,paramType = "query",dataType = "boolean")
	})
	public JSON dingdingAuthLogin(@RequestParam String code,@RequestParam String domainId,@RequestParam(required = false) String appId,@RequestParam(required = false) String formId,@RequestParam(required = false) String docId, @RequestParam(required = false, defaultValue = "false") boolean isPc) throws Exception {
		//调用钉钉api获取userId == loginno
		String userId = DdApiService.getUserInfo(code,domainId);
		//获取企业域
		DomainProcess process = AuthTimeServiceManager.domainRuntimeService();
		DomainVO domain = (DomainVO)process.doView(domainId);
		UserProcess up = AuthTimeServiceManager.userRuntimeService();
		//钉钉id查询用户
		UserVO user = (UserVO) up.doView(userId);
		//根据钉钉id和企业域名称查询用户
		if(user == null){
			user = up.getUserByDdUserIdAndDoaminName(userId,domain.getName());
		}

		String token = null;
		if(user != null){
			token = Security.getToken(user.getId());
			// 存放到cookie
			Cookie cookie = new Cookie(Security.ACCESS_TOKEN, token);
//				cookie.setHttpOnly(true);//调试方便，先注释
			cookie.setPath("/");
			response.addCookie(cookie);
		}else{
			//用户不存在时给出提示
			return result("0", "用户不存在,请联系管理员同步", null, null, null, null);
		}
		String url;
		if(!StringUtil.isBlank(formId) && !formId.equals("null")&& !StringUtil.isBlank(docId) && !docId.equals("null")){
			//链接消息中打开代办信息
			if(isPc){
				url = "portal/good/html/form.html?appId="+appId+"&docid="+docId+"&formId="+formId+"&opentarget=detail&accessToken=" + token;
			} else {
				url = "mobile/index.html#/open?linkType=00&actionContent="+formId+"&docId="+docId;
			}
		}else{
			if("pm".equals(appId)){
				url= "/pms/pm/wap/index.jsp?application=pm";// 进入系统
			}else if("qmdt".equals(appId)){
				url= "/qms/qm/wap/pendlist.jsp?application=qm";// 待填写
			}else if("qmcenter".equals(appId)){
				url= "/qms/qm/wap/center.jsp?application=qm";// 问卷中心
			}else if("amsignin".equals(appId)){
				url= "/attendance/sign.jsp?application=am&action=signin";// 签到
			}else if("amsignout".equals(appId)){
				url= "/attendance/sign.jsp?application=am&action=signout";// 签退
			}else if("am".equals(appId)){
				url= "/attendance/record.jsp?application=am";// 考勤记录
			}else if("cmfavoritecontacts".equals(appId)){
				url= "contacts/index.html?application=cm&action=favoriteContacts";// 常用
			}else if("cm".equals(appId)){
				url= "contacts/index.html?application=cm";// 通讯录
			}else if("km".equals(appId)){
				url= "/kms/kmswap/asset/index.html"; //km
			}else{
				//url= "portal/phone/main.jsp?application=" + appId;
				if(isPc){
					url="portal/good/index.html";
				} else {
					url="mobile/index.html";
				}
			}
		}

		return result("1", "登陆成功", "returnUrl", url, null, null);

	}

	/**
	 * 判断当前用户是否为其他用户的合法代理人
	 *
	 * @param user
	 * @return
	 * @throws Exception
	 */
	public boolean isAgent(BaseUser user) throws Exception {
		for (Iterator<UserVO> iterator = get_proxyUsers(user).iterator(); iterator.hasNext(); ) {
			UserVO userVO = (UserVO) iterator.next();
			//判断代理人是否代理日期过期
			if (userVO.getStartProxyTime() != null && userVO.getEndProxyTime() != null) {
				Date now = new Date();
				//过滤代理日期过期代理人
				if (now.after(userVO.getStartProxyTime()) && now.before(userVO.getEndProxyTime()))
					if (user.getId().equals(userVO.getProxyUser().getId()))
						return true;
			} else {
				if (user.getId().equals(userVO.getProxyUser().getId()))
					return true;
			}
		}
		return false;
	}

	/**
	 * 获取代理人
	 *
	 * @param baseUser
	 * @return
	 * @throws Exception
	 */
	public Collection<UserVO> get_proxyUsers(BaseUser baseUser) throws Exception {
		Collection<UserVO> proxUser = new ArrayList<UserVO>();
		UserProcess process = AuthTimeServiceManager.userRuntimeService();
		Collection<UserVO> cols = process.queryByProxyUserId(baseUser.getId());
		if (cols != null && cols.size() > 0) {
			for (Iterator<UserVO> iterator = cols.iterator(); iterator.hasNext(); ) {
				UserVO user = iterator.next();
				if (user.getStartProxyTime() != null && user.getEndProxyTime() != null) {
					Date now = new Date();
					//过滤代理日期过期代理人
					if (now.after(user.getStartProxyTime()) && now.before(user.getEndProxyTime())) {
						proxUser.add(user);
					}
				} else {
					proxUser.add(user);
				}
			}
		}
		return proxUser;
	}

	@ResponseBody
	@GetMapping(value = "/api/runtime/login/getProxyUsers/{userid}")
	@ApiOperation(value = "获取可代理登录用户", notes = "获取可代理登录用户")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "userid",value = "用户id",required = true,paramType = "path",dataType = "string")
	})
	public JSON doGetProxyUsers(@PathVariable String userid) throws Exception{
		List<UserVO> proxyUsers = getProxyUsers(userid);
		List<JSONObject> list = new ArrayList<>();
		for (UserVO user : proxyUsers) {
			JSONObject jsonObject = new JSONObject();
			jsonObject.put("id", user.getId());
			jsonObject.put("name", user.getLoginno());
			jsonObject.put("avatar", user.getAvatar());
			list.add(jsonObject);
		}
		return result("0", "", "returnUrl", "", "proxyUsers", list);
	}

	public List<UserVO> getProxyUsers(String userid) throws Exception {
		List<UserVO> users = new ArrayList<>();
		UserProcess process = AuthTimeServiceManager.userRuntimeService();
		Collection<UserVO> cols = process.queryByProxyUserId(userid);
		if (cols != null && cols.size() > 0) {
			for (Iterator<UserVO> iterator = cols.iterator(); iterator.hasNext(); ) {
				UserVO user = iterator.next();
				if (user.getStartProxyTime() != null && user.getEndProxyTime() != null) {
					Date now = new Date();
					//过滤代理日期过期代理人
					if (now.after(user.getStartProxyTime()) && now.before(user.getEndProxyTime())) {
						users.add(user);
					}
				} else {
					users.add(user);
				}
			}
		}
		return users;
	}

	@ResponseBody
	@GetMapping(value = "/api/runtime/login/loginProxy/{userid}")
	@ApiOperation(value = "代理登录", notes = "代理登录")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "userid",value = "用户id",required = true,paramType = "path",dataType = "string")
	})
	public JSON doLoginProxy(@PathVariable String userid) {
		try {
			UserProcess process = AuthTimeServiceManager.userRuntimeService();
			UserVO user = (UserVO) process.doView(userid);
			String token = Security.getToken(user.getId());
			// 存放到cookie
			Cookie cookie = new Cookie(Security.ACCESS_TOKEN, token);
//				cookie.setHttpOnly(true);//调试方便，先注释
			cookie.setPath("/");
			response.addCookie(cookie);

			String skin = PropertyUtil.getByPropName("skin", "homePage");
			return result("1", "登陆成功", "returnUrl", "../signon/dispatcher.html?skin="+skin, null, null);
		} catch (Exception e) {
			e.printStackTrace();
			return result("0", "登陆失败", "returnUrl", "", null, null);
		}
	}

	/**
	 * restful登陆接口 返回json
	 *
	 * @return
	 */
	private JSON result(String resultCode, String msg, String dataName, Object data, String dataName2, Object data2) {
		HashMap map = new HashMap();
		map.put("resultCode", resultCode);
		map.put("msg", msg);
		if (dataName != null || data != null)
			map.put(dataName, data);
		if (dataName2 != null || data2 != null)
			map.put(dataName2, data2);
		JSONObject json = JSONObject.parseObject(JSON.toJSONString(map));
		return json;
	}

	/**
	 * restful登陆接口 返回json
	 *
	 * @return
	 */
	private JSON result(String resultCode, String msg, String dataName, Object data, String dataName2, Object data2, String dataName3, Object data3) {
		HashMap map = new HashMap();
		map.put("resultCode", resultCode);
		map.put("msg", msg);
		if (dataName != null || data != null)
			map.put(dataName, data);
		if (dataName2 != null || data2 != null)
			map.put(dataName2, data2);
		if (dataName3 != null || data3 != null)
			map.put(dataName3, data3);
		JSONObject json = JSONObject.parseObject(JSON.toJSONString(map));
		return json;
	}

//    public WebCookies getWebCooikes() {
//        HttpServletRequest request = this.request;
//        HttpServletResponse response =this.response;
//
//        if (webCookies == null) {
//            webCookies = new WebCookies(request, response, WebCookies.ENCRYPTION_URL);
//        }
//
//        return webCookies;
//    }

	private char[] generateCheckCode() {
		// 定义验证码的字符表
		// 考虑到1和l难以区分,将l大写为L
		String chars = "0123456789abcdefghijkLmnopqrstuvwxyz";

		char[] rands = new char[4];
		for (int i = 0; i < 4; i++) {
			// int rand = Double.valueOf(Math.random() * 36).intValue();
			int rand = new Random().nextInt(36);
			rands[i] = chars.charAt(rand);
		}

		return rands;
	}

	/**
	 * 画干扰背景
	 *
	 * @param
	 */
	private void drawBackground(Graphics gd) {
		// 创建一个随机数生成器类
		Random r = new Random();
		gd.setColor(Color.black);
		gd.clipRect(0, 0, WIDTH + 6, HEIGHT + 4);
		// 画背景
		gd.setColor(Color.white);
		gd.fillRect(1, 1, WIDTH + 4, HEIGHT + 2);
		// 随机干扰点
//		for (int x = 3; x < WIDTH + 4; x += 4) {
//			for (int y = 2; y < HEIGHT + 3; y += 3) {
//				gd.setColor(Color.black);
//				gd.drawOval(x, y, 1, 0);
//			}
//		}
		// 随机产生160条干扰线，使图象中的认证码不易被其它程序探测到。
		for (int i = 0; i < 30; i++) {
			int x = r.nextInt(WIDTH) + 2;
			int y = r.nextInt(HEIGHT) + 3;
			int xl = r.nextInt(12);
			int yl = r.nextInt(12);
			// 产生随机的颜色分量来构造颜色值，这样输出的每位数字的颜色值都将不同。
			int red = r.nextInt(255);
			int green = r.nextInt(255);
			int blue = r.nextInt(255);

			// 用随机产生的颜色将验证码绘制到图像中。
			gd.setColor(new Color(red, green, blue));
			gd.drawLine(x, y, x + xl, y + yl);
		}
	}

	/**
	 * 生成图片
	 *
	 * @param g
	 * @param rands
	 */
	private void drawRands(Graphics g, char[] rands) {
		g.setColor(new Color(0x1f1f1f));
		// 创建字体，字体的大小应该根据图片的高度来定。
		Font font = new Font("Fixedsys", Font.PLAIN, HEIGHT);
		// 设置字体。
		g.setFont(font);
		int xx = WIDTH / (rands.length + 1);
		int codeY = HEIGHT;
		for (int i = 0; i < rands.length; i++) {
			g.drawString("" + rands[i], (i + 1) * xx, codeY);
		}
	}

	private static int WIDTH = 60;

	private static int HEIGHT = 20;

	private String CheckCode_Session = "CheckCode";

	public String getCheckCodeImg() throws Exception {
		String png_base64;
		response.setContentType("image/jpg");
		response.setHeader("Pragma", "No-cache");
		response.setHeader("Cache-Control", "no-cache");
		response.setDateHeader("Expires", 0);
		// 创建内存图象并获得其图形上下文
		BufferedImage image = new BufferedImage(WIDTH + 6, HEIGHT + 4, BufferedImage.TYPE_INT_RGB);
		Graphics g = image.getGraphics();
		// 产生随机的认证码
		char[] rands = generateCheckCode();
		// 产生图像
		drawBackground(g);
		drawRands(g, rands);
		// 结束图像的绘制过程，完成图像
		g.dispose();
		// 转base64
//		BASE64Encoder encoder = new BASE64Encoder();
		ByteArrayOutputStream baos = new ByteArrayOutputStream();// io流
		ImageIO.write(image, "JPG", baos);// 写入流中
		byte[] bytes = baos.toByteArray();// 转换成字节
		png_base64 = Base64Util.encode(bytes);// 转换成base64串
//		png_base64 = encoder.encodeBuffer(bytes).trim();// 转换成base64串
		// 删除 \r\n
		png_base64 = png_base64.replaceAll("\n", "").replaceAll("\r", "");
		request.getSession().setAttribute(CheckCode_Session, String.valueOf(rands));
		return png_base64;
	}


	/**
	 * restful登陆接口 获取企业域列表
	 *
	 * @return
	 */
	@ResponseBody
	@GetMapping(path = "/api/debuglogin/getDomainList")
	@ApiOperation(value = "调试登录-获取企业域列表", notes = "调试登录-获取企业域列表")
	public JSON getDomainList(HttpServletResponse response, HttpServletRequest request) throws Exception {
		try {
			Collection<String> domainList = getDomainNameList();
			return result("1", "成功", "domainList", domainList, null, null);
		} catch (Exception e) {
			return result("0", "失败", "domainList", null, null, null);
		}
	}

	/**
	 * 获取所有企业域名
	 * @return 所有企业域名称列表
	 */
	public Collection<String> getDomainNameList(){
		Collection<String> map = new ArrayList<String>();
		try {
			DomainProcess process = AuthTimeServiceManager.domainRuntimeService();;
			Collection<DomainVO> col = process.getDomainByStatus(1);
			Iterator<DomainVO> it = col.iterator();
			while(it.hasNext()){
				DomainVO vo = it.next();
				map.add(vo.getName());
			}
			return map;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return map;
	}

	/**
	 * restful登陆接口 获取用户列表
	 *
	 * @return
	 */
	@ResponseBody
	@GetMapping(path = "/api/debuglogin/getUserList")
	@ApiOperation(value = "调试登录-获取用户列表", notes = "调试登录-获取用户列表")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "domainName",value = "企业域名称",required = true,paramType = "query",dataType = "string"),
			@ApiImplicitParam(name = "username",value = "用户名",required = true,paramType = "query",dataType = "string")
	})
	public JSON getUserList(@RequestParam(required = true) String domainName ,@RequestParam(required = false) String username) {
		try {
//            DomainDAO domainDAO = (DomainDAO) DAOFactory.getDefaultDAO(DomainVO.class.getName());
//            final DomainVO domain = domainDAO.getDomainByName(domainName);
//            if (domain == null || domain.getStatus() == 0) {
//                return result("0", "企业域不存在", "returnUrl", "", "checkcodeImg", "");
//            }
			UserProcess process = AuthTimeServiceManager.userRuntimeService();
			Collection<UserVO> userVOS = process.getUserByLoginnoLikeAndDoaminName(domainName,username,1,10);

			Collection<String> map = new ArrayList<String>();
			Iterator<UserVO> it = userVOS.iterator();
			while(it.hasNext()){
				UserVO vo = it.next();
				map.add(vo.getLoginno());
			}

			return result("1", "成功", "userList", map, null, null);
		} catch (Exception e) {
			return result("0", "失败", "userList", null, null, null);
		}
	}


	/**
	 * restful登陆接口 获取登陆页面所需的多语言字段
	 *
	 * @param request
	 * @return
	 */
	@ResponseBody
	@GetMapping(path = "/api/debuglogin/getMultiLangWordList")
	@ApiOperation(value = "调试登录-获取登陆页面所需的多语言字段", notes = "调试登录-获取登陆页面所需的多语言字段")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "language",value = "语言",required = true,paramType = "query",dataType = "string")
	})
	public JSON getMultiLangWordList(@RequestParam String language, HttpServletRequest request) {
		Map MultiLangWordMap;
		try {
			MultiLangWordMap = getLoginMultiLangWordList(language);

			Cookie cookie = new Cookie(Web.SESSION_ATTRIBUTE_USERLANGUAGE, language);
			cookie.setPath("/");
			cookie.setMaxAge(7200);
			response.addCookie(cookie);

			return result("1", "成功", "multiLangWordList", MultiLangWordMap, null, null);
		} catch (Exception e) {
			return result("0", "失败", "multiLangWordList", null, null, null);
		}
	}


	@ResponseBody
	@PostMapping("/api/debuglogin/loginWithCiphertext2")
	@ApiOperation(value = "调试登录-登陆", notes = "调试登录-登陆")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "domainName",value = "企业域名称",required = true,paramType = "query",dataType = "string"),
			@ApiImplicitParam(name = "username",value = "用户名",required = true,paramType = "query",dataType = "string")
	})
	public JSON login2(@RequestBody JSONObject jsonObj) throws Exception {
		String domainName = jsonObj.getString("domainName");
//        String domainName = "我的公司";
		String username = jsonObj.getString("username").split("\\(")[0];
//        String username = "test";
		try {
			//ekko 根据帐号查询用户
			UserProcess up = AuthTimeServiceManager.userRuntimeService();
			UserVO userVO = up.getUserByLoginnoAndDoaminName(username, domainName);
			String token = Security.getToken(userVO.getId());
			String skin = PropertyUtil.getByPropName("skin", "homePage");
			// 存放到cookie
			Cookie cookie = new Cookie(Security.DEBUG_TOKEN, token);
//				cookie.setHttpOnly(true);//调试方便，先注释
			cookie.setPath("/");
			response.addCookie(cookie);
			if (this.isAgent(userVO)) {
				return result("1", "代理登陆页面", "returnUrl", "../login/agent.html?id="+userVO.getId(), null, null);
			}
			return result("1", "登陆成功", "returnUrl", "../signon/dispatcher.html?skin="+skin, "checkcodeImg", "");
		} catch (Exception e) {
			return result("0", "登陆失败", "returnUrl", "", "checkcodeImg", "");
		}

	}

	/**
	 * 退出登录
	 * @return
	 */
	@ResponseBody
	@PostMapping(path = "/api/runtime/logout")
	@ApiOperation(value = "退出登录", notes = "退出登录")
	public JSON logout() throws Exception {
		//用户注销时清除Cookie
		CookieUtil.clearCookie("verify_login", response);
		CookieUtil.clearCookie("autologin", response);
		CookieUtil.clearCookie(Security.ACCESS_TOKEN, response);
		CookieUtil.clearCookie("isFromLogin", response);
		HttpSession session = request.getSession();
		session.removeAttribute("SPRING_SECURITY_CONTEXT");

		/*
		CompletableFuture future = CompletableFuture.runAsync(() -> {
			String userId = this.getCurrentUserId(request);
			if (StringUtils.hasLength(userId)) {
				SpringApplicationContextUtil.getBean(DistributedCacheProvider.class)
						.remove(CacheConst.getUserRoleDeptKmsRelationCacheKey(userId));
			}
		});

		future.get(2, TimeUnit.SECONDS);
		 */

		return result("ok", "ok", "data", "/static/signon/index.html?yes=1", null, null);
	}

	@PostMapping(value = "/api/runtime/login/smsSend")
	@ApiOperation(value = "发送短信验证码", notes = "发送短信验证码")
	public JSON doSmsSend(String userId,String content) {
		/*
		boolean status = false;
		try{
			UserProcess up = (UserProcess) ProcessFactory.createProcess(UserProcess.class);
			UserVO user = (UserVO) up.doView(userId);
			SendMode sender = new SMSMode();
			sender.send("", 0, content, user, null, user);
			status = true;
		}catch (Exception e){
			e.printStackTrace();
		}


		 */
		return result("ok", "发送成功", "status", true, null, null);
	}


	/**
	 * 获取注销重定向链接
	 *
	 * @return 注销重定向链接
	 */
	public String getLogoutRedirect(HttpServletRequest request, HttpServletResponse response) {
		String url = "";
		if (Web.AUTHENTICATION_TYPE_SSO.equals(PropertyUtil.get(Web.AUTHENTICATION_TYPE))) {
			url = PropertyUtil.get(Web.SSO_LOGOUT_REDIRECT);
		} else {
			//url = request.getContextPath() + getDispatchURL("/", request, response);
			url = "/signon/";
		}
		return url;
	}

	public String getDispatchURL(String url, ServletRequest req, ServletResponse res) {
		if(StringUtil.isBlank(url)){
			return null;
		}

		if (url.indexOf("/portal/dispatch/") != -1) {
			HttpServletRequest hreq = (HttpServletRequest) req;
			HttpSession session = hreq.getSession();
			String skinType = (String) session.getAttribute("SKINTYPE");
			if (skinType == null)
				skinType = "H5";

			url = url.replace("dispatch", skinType);
		}
		return url;
	}

	@RequestMapping("/api/runtime/login/getMenuList")
	public AjaxResult getMenuList() throws Exception {
		return AjaxResult.success(null,this.getMenus());
	}

	@RequestMapping("/api/runtime/login/getPoliceRoles")
	public AjaxResult getPoliceRoles(String roleNo, String roleName, Map<String,String> menuIdMap) throws Exception {
		return AjaxResult.success(null,getPoliceRoleList(roleNo,roleName,menuIdMap));
	}



	public JSONArray getMenus() throws Exception {
		//获取软件列表
		ApplicationDesignTimeService appService = DesignTimeServiceManager.applicationDesignTimeService();
		List<Application> list = appService.list("", null);

		JSONArray array = new JSONArray();
		ResourceDesignTimeService resourceDesignTimeService = DesignTimeServiceManager.resourceDesignTimeService();

		int index = 1;
		for (Application application : list) {
			if(application.getName().contains("平台运营管理")|| application.getName().contains("组织权益")){
				continue;
			}
			List<ResourceVO> menusList = resourceDesignTimeService.deepQueryAll(application.getId(), ModelSuffix.MENU_FILE_SUFFIX);

			if(menusList == null || menusList.size() == 0){
				continue;
			}
			JSONObject jsonObject = new JSONObject();
			jsonObject.put("id",application.getId());
			jsonObject.put("name",application.getName());
			jsonObject.put("seq",index++);
			array.add(jsonObject);
			for (ResourceVO resourceVO : menusList) {
				JSONObject subObj = new JSONObject();
				subObj.put("id",resourceVO.getId());
				subObj.put("name",resourceVO.getName());
				subObj.put("parentId",resourceVO.getParentId());
				subObj.put("seq",resourceVO.getOrderno());

				array.add(subObj);
				if(resourceVO.getChildren() != null && resourceVO.getChildren().size() > 0) {
					getSubMenuList(array,resourceVO);
				}
			}
		}
		return array;
	}


	public void getSubMenuList(JSONArray array,ResourceVO parentVo) throws Exception {
		for (ResourceVO resourceVO : parentVo.getChildren()) {
			JSONObject subObj = new JSONObject();
			subObj.put("id",resourceVO.getId());
			subObj.put("name",resourceVO.getName());
			subObj.put("parentId",resourceVO.getParentId());
			subObj.put("seq",resourceVO.getOrderno());
			array.add(subObj);
			if(resourceVO.getChildren() != null && resourceVO.getChildren().size() > 0) {
				getSubMenuList(array,resourceVO);
			}
		}
	}


	/**
	 * 获取角色
	 * 没有则创建，有则更新
	 * @param roleNo
	 * @param roleName
	 * @return
	 * @throws Exception
	 */
	public List<String> getPoliceRoleList(String roleNo,String roleName,Map<String,String> menuIdMap) throws Exception {
		RoleDesignTimeService roleDesignTimeService = AuthTimeServiceManager.roleRuntimeService();
		List<String> roleList = new ArrayList<>();
		//获取软件列表
		ApplicationDesignTimeService appService = DesignTimeServiceManager.applicationDesignTimeService();
		List<Application> list = appService.list("", null);

		if(list.size()== 0){
			return roleList;
		}

		//需要移除的资源id集合
		List<String> removeResIdList = new ArrayList<String>();
		//新增的资源对象集合
		List<Permission> permissionList = new ArrayList<Permission>();

		for(Iterator<Application> iterator =list.iterator();iterator.hasNext();){
			Application application = iterator.next();
			if(Application.SYSTEM_TYPE == application.getType()){
				continue;
			}

			Role role = roleDesignTimeService.findByRoleNo(roleNo,application.getId());
			if(role == null){
				role = new Role();
				role.setRoleNo(roleNo);
				role.setStatus(1);
				role.setName(roleName);
				role.setParentId(application.getId());
				role.setApplicationid(application.getId());
				role.setSortId(Sequence.getTimeSequence());
				role.setId(Sequence.getDesignTimeSequence());
				roleDesignTimeService.save(role);
			}

			ResourceDesignTimeService resourceDesignTimeService = DesignTimeServiceManager.resourceDesignTimeService();
			List<ResourceVO> menusList = resourceDesignTimeService.deepQueryAll(application.getId(), ModelSuffix.MENU_FILE_SUFFIX);

			for (ResourceVO resourceVO : menusList) {
				removeResIdList.add(resourceVO.getId());
				if(ResourceVO.PERMISSION_TYPE_PUBLIC.equals(resourceVO.getPermissionType())){
					Permission permission = PermissionUtil.createPermissionResource(role.getId(), resourceVO.getId());
					permissionList.add(permission);
					continue;
				}
				if(menuIdMap.get(resourceVO.getId()) != null){
					Permission permission = PermissionUtil.createPermissionResource(role.getId(), resourceVO.getId());
					permissionList.add(permission);
				}
				getSubMenuPermission(resourceDesignTimeService,role.getId(),menuIdMap,resourceVO.getId(),removeResIdList,permissionList);
			}

			PermissionUtil.removeAuth(removeResIdList, role);
			PermissionUtil.pushAuth(permissionList, role);
			roleDesignTimeService.update(role);
			roleList.add(role.getId());
		}

		//清除redis中的缓存
		Environment.cleanPermissionMap();
		//初始化
		PermissionUtil.initPermissionMap();
		return roleList;
	}


	/**
	 * 获取下级菜单权限
	 * @param roleId
	 * @param menuIdMap
	 * @param parentId
	 * @param removeResIdList
	 * @param permissionList
	 * @throws Exception
	 */
	private void getSubMenuPermission(ResourceDesignTimeService resourceDesignTimeService ,String roleId,Map<String,String> menuIdMap,String parentId,List<String> removeResIdList,List<Permission> permissionList) throws Exception {
		List<ResourceVO> menusList = resourceDesignTimeService.getChildsByParentId(parentId, "");
		if(menusList != null && menusList.size() > 0){
			for (ResourceVO resourceVO : menusList) {
				removeResIdList.add(resourceVO.getId());
				if(ResourceVO.PERMISSION_TYPE_PUBLIC.equals(resourceVO.getPermissionType())){
					Permission permission = PermissionUtil.createPermissionResource(roleId, resourceVO.getId());
					permissionList.add(permission);
					continue;
				}
				if(menuIdMap.get(resourceVO.getId()) != null){
					Permission permission = PermissionUtil.createPermissionResource(roleId, resourceVO.getId());
					permissionList.add(permission);
				}
				getSubMenuPermission(resourceDesignTimeService,roleId,menuIdMap,resourceVO.getId(),removeResIdList,permissionList);
			}
		}
	}
}
