package cn.com.qmth.stmms.open.controller;

import java.util.Date;

import cn.com.qmth.stmms.biz.school.model.School;
import cn.com.qmth.stmms.biz.school.service.SchoolService;
import cn.com.qmth.stmms.biz.user.model.User;
import cn.com.qmth.stmms.biz.user.service.UserService;
import cn.com.qmth.stmms.common.authorization.AuthorizationService;
import cn.com.qmth.stmms.common.domain.WebUser;
import cn.com.qmth.stmms.common.enums.Role;
import cn.com.qmth.stmms.common.session.model.StmmsSession;
import cn.com.qmth.stmms.common.session.service.SessionService;
import cn.com.qmth.stmms.common.signature.SignatureInfo;
import cn.com.qmth.stmms.common.signature.SignatureType;
import cn.com.qmth.stmms.common.utils.RequestIPUtil;
import cn.com.qmth.stmms.common.utils.RequestUtils;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
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.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Controller("openUserController")
@RequestMapping("/open")
public class OpenUserController {

    @Autowired
    private SessionService sessionService;

    @Autowired
    private AuthorizationService authorizationService;

    @Autowired
    private UserService userService;

    @Autowired
    private SchoolService schoolService;

    @RequestMapping(value = "/mark/login", method = RequestMethod.POST)
    public String markLogin(HttpServletRequest request, HttpServletResponse response, RedirectAttributes redirect,
            @RequestParam Long time, @RequestParam String authorization, @RequestParam String account,
            @RequestParam String name, @RequestParam String returnUrl, @RequestParam(required = false) String schoolCode) {
        // 请求参数验证
        authorization = StringUtils.trimToEmpty(authorization);
        name = StringUtils.trimToNull(name);
        account = StringUtils.trimToEmpty(account);
        returnUrl = StringUtils.trimToEmpty(returnUrl);
        if (time == null) {
            return errorRedirect(redirect, null, "time不能为空");
        }
        if (authorization.length() == 0) {
            return errorRedirect(redirect, null, "authorization不能为空");
        }
        if (returnUrl.length() == 0) {
            return errorRedirect(redirect, null, "returnUrl不能为空");
        }
        if (account.length() == 0) {
            return errorRedirect(redirect, returnUrl, "account不能为空");
        }
        // 签名验证，获取访问学校
        School school = null;
        SignatureInfo info = authorizationService.buildSignature(time, authorization, request.getMethod(),
                request.getServletPath());
        if (info != null && info.getType() == SignatureType.SECRET) {
            school = schoolService.findByAccessKey(info.getInvoker());
        }
        if (school == null || !school.isEnable() || !info.validate(school.getAccessSecret())) {
            return errorRedirect(redirect, returnUrl, "鉴权失败");
        }
        if (StringUtils.isNotBlank(schoolCode)) {
            String subCode = school.getCode() + "-" + schoolCode;
            school = schoolService.findByParentIdAndSubCode(school.getId(), subCode);
            if (school == null || !school.isEnable()) {
                return errorRedirect(redirect, returnUrl, "鉴权失败");
            }
        }
        // 查找第三方账号并登陆
        User user = userService.externalLogin(school.getId(), account, name, null, Role.MARKER);
        if (user == null) {
            return errorRedirect(redirect, returnUrl, "第三方登录异常");
        }
        if (!user.isEnable()) {
            return errorRedirect(redirect, returnUrl, "第三方账号已禁用");
        }
        if (user.getRole() != Role.MARKER) {
            return errorRedirect(redirect, returnUrl, "第三方账号没有评卷权限");
        }
        user.setLastLoginTime(new Date());
        user.setLastLoginIp(RequestIPUtil.getIpAddress(request));
        user = userService.save(user);
        // 保存第三方账号到session
        StmmsSession session = RequestUtils.getSession(request);
        WebUser wu = new WebUser(user);
        wu.setLogoutUrl(returnUrl);
        session.saveWebUser(wu);
        sessionService.put(request, response, session);
        return "redirect:/mark/subject-select";
    }

    @RequestMapping(value = "/error")
    public ModelAndView error(HttpServletRequest request, @RequestParam(required = false) String message,
            @RequestParam(required = false) String returnUrl) {
        ModelAndView modelAndView = new ModelAndView("modules/open/error");
        modelAndView.addObject("message", StringUtils.trimToNull(message));
        modelAndView.addObject("returnUrl", StringUtils.trimToNull(returnUrl));
        return modelAndView;
    }

    private String errorRedirect(RedirectAttributes redirect, String returnUrl, String... errors) {
        if (errors != null && errors.length > 0) {
            redirect.addFlashAttribute("message", StringUtils.join(errors, "\n"));
        }
        if (returnUrl != null && returnUrl.length() > 0) {
            redirect.addFlashAttribute("returnUrl", returnUrl);
        }
        return "redirect:/open/error";
    }

    @RequestMapping(value = "/subject_header/login", method = RequestMethod.POST)
    public String subjectHeaderLogin(HttpServletRequest request, HttpServletResponse response,
            RedirectAttributes redirect, @RequestParam Long time, @RequestParam String authorization,
            @RequestParam String account, @RequestParam String name, @RequestParam String returnUrl,
            @RequestParam(required = false) String schoolCode) {
        // 请求参数验证
        authorization = StringUtils.trimToEmpty(authorization);
        name = StringUtils.trimToNull(name);
        account = StringUtils.trimToEmpty(account);
        returnUrl = StringUtils.trimToEmpty(returnUrl);
        if (time == null) {
            return errorRedirect(redirect, null, "time不能为空");
        }
        if (authorization.length() == 0) {
            return errorRedirect(redirect, null, "authorization不能为空");
        }
        if (returnUrl.length() == 0) {
            return errorRedirect(redirect, null, "returnUrl不能为空");
        }
        if (account.length() == 0) {
            return errorRedirect(redirect, returnUrl, "account不能为空");
        }
        // 签名验证，获取访问学校
        School school = null;
        SignatureInfo info = authorizationService.buildSignature(time, authorization, request.getMethod(),
                request.getServletPath());
        if (info != null && info.getType() == SignatureType.SECRET) {
            school = schoolService.findByAccessKey(info.getInvoker());
        }
        if (school == null || !school.isEnable() || !info.validate(school.getAccessSecret())) {
            return errorRedirect(redirect, returnUrl, "鉴权失败");
        }
        if (StringUtils.isNotBlank(schoolCode)) {
            String subCode = school.getCode() + "-" + schoolCode;
            school = schoolService.findByParentIdAndSubCode(school.getId(), subCode);
            if (school == null || !school.isEnable()) {
                return errorRedirect(redirect, returnUrl, "鉴权失败");
            }
        }
        // 查找第三方账号并登陆
        User user = userService.externalLogin(school.getId(), account, name, null, Role.SUBJECT_HEADER);
        if (user == null) {
            return errorRedirect(redirect, returnUrl, "第三方登录异常");
        }
        if (!user.isEnable()) {
            return errorRedirect(redirect, returnUrl, "第三方账号已禁用");
        }
        if (user.getRole() != Role.SUBJECT_HEADER) {
            return errorRedirect(redirect, returnUrl, "第三方账号没有评卷组长权限");
        }
        user.setLastLoginTime(new Date());
        user.setLastLoginIp(RequestIPUtil.getIpAddress(request));
        user = userService.save(user);
        // 保存第三方账号到session
        StmmsSession session = RequestUtils.getSession(request);
        WebUser wu = new WebUser(user);
        wu.setLogoutUrl(returnUrl);
        session.saveWebUser(wu);
        sessionService.put(request, response, session);
        return "redirect:/admin/exam/select";
    }
}
