package com.reyun.controller.manage;

import com.dianping.cat.Cat;
import com.reyun.dic.LogEnumType;
import com.reyun.model.Account;
import com.reyun.model.App;
import com.reyun.repository.AccountRepository;
import com.reyun.repository.BussinessManRepository;
import com.reyun.repository.SystemParamRepository;
import com.reyun.service.AppService;
import com.reyun.service.AuthService;
import com.reyun.service.RegedService;
import com.reyun.service.UserLogService;
import com.reyun.util.CipherUtil;
import com.reyun.util.Constant;
import com.reyun.util.DateUtil;
import com.reyun.util.HashAlgorithms;
import com.reyun.util.HttpClientUtil;
import com.reyun.util.IPAddrUtil;
import com.reyun.util.MailUtils;
import com.reyun.util.RedisUtilNew;
import com.reyun.util.ResultModel;
import com.reyun.util.StringUtil;
import com.reyun.util.ValidateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
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.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Controller
@RequestMapping("reged")
public class RegedController {

	protected Logger logger = LoggerFactory.getLogger(RegedController.class);

	@Autowired
	AppService appService;

	@Autowired
	RegedService regedService;

	@Autowired
	AccountRepository accountRepository;

	@Autowired
	UserLogService userLogService;

	@Autowired
	BussinessManRepository bussinessManRepository;

	@Autowired
	AuthService authService;

	@Autowired
	BussinessManRepository bussinessRepository;

	@Autowired
	SystemParamRepository systemParamRepository;

	private static final String VERIFY_EMAIL_SEND_URL = Constant.adminUrl + "/api/tool/account/sendemail/";

	private static final String ACTIVE_EMAIL_SEND_URL = Constant.accountCheckUrl + "/api/reged/active/";

	private static final int VALID_EMAIL_EXPIRE_TIME = 5;

	/**
	 * 网站首页注册帐号并发送激活邮件
	 * @param request
	 * @param resource
	 * @return
	 */
	@RequestMapping(value = "regedaccount",method = RequestMethod.POST)
	@ResponseBody
	public ResultModel createOrigi(HttpServletRequest request, @RequestBody Account resource) {
		Cat.logMetricForCount("帐号注册(首页)");

		Account accountDB = authService.check(resource.getEmail());
		if (accountDB != null) {
			return new ResultModel(-1,"该邮箱已存在，请更换邮箱", "该邮箱已存在，请更换邮箱");
		}

		//1. 创建帐号
		resource.setPassword(CipherUtil.generatePassword(resource.getPassword()));

		//表示未激活
		resource.setStatus(-3);
		resource.setIsSuperUser(true);
		resource.setIsChannelPerson(false);
		resource.setActiveTime(System.currentTimeMillis());
		resource.setActiveStatus(false);
		resource.setRoleCategory(0L);
		resource.setDelFlag(false);
		try {
			resource.setRegIpAddr(IPAddrUtil.getIpAddr(request));
			resource.setRegIpLocation(IPAddrUtil.getLocationFromIpAddr(resource.getRegIpAddr()));
		} catch (Exception e1) {
			logger.error("fail to get region by ip," + e1.getMessage());
		}
		Account account = accountRepository.save(resource);

		//更新rootParent
		account.setRootParent(account.getId());
		accountRepository.save(account);

		String token = HashAlgorithms.MD5("superuser_" + account.getId() + account.getActiveTime());

		//2.发送邮件，激活
		String activeInterfaceUrl = ACTIVE_EMAIL_SEND_URL+0+token+resource.getId();

		String subject = "Io账号激活";

		StringBuilder content = new StringBuilder();
		content.append("<!doctype html> <html><head></head><body> ")
				.append("亲爱的用户：</br>")
				.append("您好，您于").append(DateUtil.format(new Date(account.getActiveTime()),DateUtil.C_TIME_PATTON_DEFAULT))
				.append("注册热云账号").append(account.getEmail())
				.append("，以下链接激活账号</br>")
				.append("<a href=\"" + activeInterfaceUrl + "\">").append(activeInterfaceUrl).append("</a>")
				.append("</body></html>");

		String contents = content.toString();
		List<String> list = new ArrayList<>();

		list.add(account.getEmail());

		try {
			Long beforeTime=new Date().getTime();
			MailUtils.sendHtmlEmail(subject,contents,list);
			Long afterTime=new Date().getTime();
			long useTime = afterTime - beforeTime;
			logger.info("发邮件耗时"+useTime+"毫秒。");
		} catch (Exception e) {
			logger.error(e.getMessage(),e);
			return new ResultModel(250,"邮件发送失败", "邮件发送失败");
		}

		if(!ValidateUtil.isValid(account)){
			return new ResultModel(201,"注册失败", "注册失败");
		}
		userLogService.insertLog(account, LogEnumType.REGED.getCode(), LogEnumType.REGED.getName() + account.getEmail(), account, null, null, request);

		return ResultModel.OK(account);
	}

	/**
	 * 激活账号，同时发送验证邮件
	 * @param httpServletRequest
	 * @param message flag（0,1）+token（32位）+ id
	 * @return
	 * @throws IOException
	 */
	@RequestMapping(value = "active/{message}" ,method = RequestMethod.GET)
	@ResponseBody
	public ModelAndView active(HttpServletRequest httpServletRequest,@PathVariable String message) throws IOException {
		Cat.logMetricForCount("帐号激活");

		String flagstr = message.substring(0,1);
		String tokenstr = message.substring(1,33);
		String idstr = message.substring(33,message.length());
		//验证url（token合法性，日期的时效性,url是否重复提交）

		logger.info(idstr);
		logger.info(tokenstr);

		String activeResult = this.regedService.active(tokenstr,Long.parseLong(idstr));

		Account account = this.accountRepository.findOne(Long.parseLong(idstr));
		logger.info("activeResult = "+activeResult);
		if("success".equals(activeResult))
		{
			Account one = this.accountRepository.findOne(Long.parseLong(idstr));
			//flag=1表示老用户激活
			//flag=0表示新用户激活  防止二次点击修改status
			if(flagstr.equals("0") && one.getStatus()!= -1)
			{
				one.setStatus(-2);
			}
			one.setActiveStatus(true);
			one.setFlowRestrict(true);
			Account result = this.accountRepository.save(one);
			logger.info(result.toString());

			//加上判断,防止多次点击  和 老用户不用审核
			if(one.getStatus() != -1 && "0".equals(flagstr)) {
				/**
				 * 激活成功发送审核请求
				 */
				String ip = "unknown";
				try {
					ip = IPAddrUtil.getIpAddr(httpServletRequest);
				} catch (Exception e) {
					e.printStackTrace();
				}
				if (RedisUtilNew.getInstance().tryLock(account.getEmail()+account.getId(), VALID_EMAIL_EXPIRE_TIME) != null) {
					logger.info("enter trylock_____________");
					this.regedService.verifyAccount(result, ip);
				}
				else
				{
					logger.info("重复的审核请求");
				}
			}

			return new ModelAndView("redirect:/success.html");
		}
		else if("repeat url".equals(activeResult))
		{
			return new ModelAndView("redirect:/success.html");
		}
		else
		{
			//url验证失败，返回失败界面，并带上参数
			return new ModelAndView("redirect:/failure.html#?message="+flagstr+account.getId());
		}
	}

	/**
	 * 激活后审核接口
	 * @param httpServletRequest
	 * @param id
	 * @return
	 */
	@RequestMapping(value = "verify/{id}" ,method = RequestMethod.GET)
	@ResponseBody
	public ResultModel verify(HttpServletRequest httpServletRequest,@PathVariable Long id)
	{
		Cat.logMetricForCount("帐号审核");

		Account account = this.accountRepository.findOne(id);

		//状态改为审核中
		account.setStatus(-1);
		account.setVerifyEmail(false);
		Account result = this.accountRepository.save(account);

		String token = HashAlgorithms.MD5("superuser_" + id);
		String ipAddr = IPAddrUtil.getIpAddr(httpServletRequest);

		//审核
		logger.info("调用office系统接口, 发送审核邮件. accountid: {}", account.getId());
		final String sendEmailUrl = VERIFY_EMAIL_SEND_URL + account.getId() + "/" + token + "?ip=" + (StringUtil.isEmpty(ipAddr) ? "" : ipAddr);
		String reqResult = HttpClientUtil.doHttpGetRequest(sendEmailUrl, "io");		logger.info("调用office系统接口, 发送审核邮件. accountid: {}, result:{}", account.getId(), reqResult);

		return ResultModel.OK(result);
	}

	/**
	 * 修改用户email
	 * @param id
	 * @param oldemail
	 * @param newemail
	 * @return
	 */
	@RequestMapping(value = "modifyemail/{id}" ,method = RequestMethod.GET)
	@ResponseBody
	public ResultModel modifyemail(@PathVariable Long id ,@RequestParam String oldemail,@RequestParam String newemail)
	{
		Account one = this.accountRepository.findOne(id);

		//验证新邮箱唯一性
		Account accountDB = authService.check(newemail);
		if (accountDB != null) {
			return new ResultModel(-1,"该邮箱已存在，请更换邮箱", "该邮箱已存在，请更换邮箱");
		}

		//验证用户是否已激活
		if(one.getStatus() >= -2 )
		{
			return new ResultModel(251,"邮箱已激活", "邮箱已激活");
		}

		/**
		 * 重新发送激活邮件
		 */

		//重置状态
		one.setActiveTime(new Date().getTime());
		one.setActiveStatus(false);

		Account account = this.accountRepository.save(one);

		String token = HashAlgorithms.MD5("superuser_" + account.getId()+account.getActiveTime());


		//判断新老用户
		int flag = 0;
		if(one.getStatus()==1)
		{
			flag = 1;
		}
		//2.发送邮件，激活
		String activeInterfaceUrl = ACTIVE_EMAIL_SEND_URL+flag+token+account.getId();

		Boolean emialResult = this.regedService.sendactivewhenUpdateEmail(activeInterfaceUrl,newemail,one.getActiveTime());

		//验证激活邮件是否成功
		if(emialResult == false)
		{
			return new ResultModel(250,"邮件发送失败", "邮件发送失败");
		}
		Account result = this.regedService.modifyEmail(id,oldemail,newemail);
		return ResultModel.OK(result);
	}

	/**
	 * 发送激活邮件
	 * @param id
	 * @param flag 0：新用户  1;老用户
	 * @return
	 */
	@RequestMapping(value = "sendeactivemail/{id}/{flag}" ,method = RequestMethod.GET)
	@ResponseBody
	public ResultModel sendemail(@PathVariable Long id,@PathVariable Integer flag)
	{

		String result = "failure";
		Account account = this.accountRepository.findOne(id);

		//判断用户是否已经激活
		if (account.getStatus() > -2 && flag == 0) {

			result = "actived";

		} else if (account.getIsSuperUser()) {
			//更新激活时间
			account.setActiveTime(new Date().getTime());
			account.setActiveStatus(false);
			this.accountRepository.save(account);

			String token = HashAlgorithms.MD5("superuser_" + id + account.getActiveTime());

			String activeInterfaceUrl = ACTIVE_EMAIL_SEND_URL + flag + token + id;
			Boolean emailResult = this.regedService.sendActiceEmail(activeInterfaceUrl, account.getId());

			if (emailResult) {
				result = "success";
			} else {
				return new ResultModel(250, "邮件发送失败", "邮件发送失败");
			}

		}

		return ResultModel.OK(result);
	}

	/**
	 * 用户忘记密码邮件请求
	 * @param email
	 * @return
	 */
	@RequestMapping(value = "sendforgetpwdemail" ,method = RequestMethod.GET)
	@ResponseBody
	public ResultModel sendForgetPwdEmail(@RequestParam String email)
	{
		Map<String,Object> result = this.regedService.sendForgetPwdEmail(email);
		if("send email error".equals(result.get("message")))
		{
			return new ResultModel(250,"邮件发送失败", "邮件发送失败");
		}
		return ResultModel.OK(result);
	}

	/**
	 * 邮件确认后修改密码
	 * @param id
	 * @param pwd
	 * @return
	 */
	@RequestMapping(value = "updatepwd/{id}" ,method = RequestMethod.POST)
	@ResponseBody
	public ResultModel updatePwd(@PathVariable Long id,@RequestBody Map<String,String> pwd)
	{
		String result = "";
		Account account = this.accountRepository.findOne(id);
		if(ValidateUtil.isValid(account))
		{
			if("admin@reyun.com".equals(account.getEmail())||"demo@reyun.com".equals(account.getEmail()))
			{
				result = "该账号密码不能修改";
			}
			else
			{
				result = this.regedService.updatepwd(id,pwd.get("newpwd"),pwd.get("token"));
			}

		}
		else
		{
			result = "invalid request";
		}
		return ResultModel.OK(result);
	}

	@RequestMapping(value = "validatepass" ,method = RequestMethod.GET)
	@ResponseBody
	public ResultModel validatePass(@RequestParam String message)
	{
		String result = this.regedService.validatepass(message);
		return ResultModel.OK(result);
	}

	@RequestMapping(value = "find/{id}" ,method = RequestMethod.GET)
	@ResponseBody
	public ResultModel validatePass(@PathVariable Long id)
	{
		Account result = this.accountRepository.findOne(id);
		return ResultModel.OK(result);
	}

	@RequestMapping(value = "findbyemail" ,method = RequestMethod.GET)
	@ResponseBody
	public ResultModel findbyemail(@RequestParam String email)
	{
		Account result = this.accountRepository.findAccountByEmail(email);
		if (result != null) {
			List<App> appList = appService.listAppByAccount(result.getId());
			result.setAppSize(appList.size());
		}
		return ResultModel.OK(result);
	}
}
