package com.qmth.exam.reserve.service.impl;

import com.qmth.boot.core.exception.StatusException;
import com.qmth.boot.core.security.annotation.AuthorizationComponent;
import com.qmth.boot.core.security.service.AuthorizationService;
import com.qmth.boot.tools.signature.SignatureType;
import com.qmth.boot.tools.uuid.FastUUID;
import com.qmth.exam.reserve.bean.applytask.CurrentApplyTaskVO;
import com.qmth.exam.reserve.bean.login.LoginReq;
import com.qmth.exam.reserve.bean.login.LoginUser;
import com.qmth.exam.reserve.bean.login.WechatLoginReq;
import com.qmth.exam.reserve.bean.org.OrgInfo;
import com.qmth.exam.reserve.cache.impl.ApplyTaskCacheService;
import com.qmth.exam.reserve.cache.impl.LoginSessionManager;
import com.qmth.exam.reserve.cache.impl.OrgCacheService;
import com.qmth.exam.reserve.entity.ApplyTaskEntity;
import com.qmth.exam.reserve.entity.StudentEntity;
import com.qmth.exam.reserve.entity.UserEntity;
import com.qmth.exam.reserve.enums.Role;
import com.qmth.exam.reserve.service.ApplyTaskService;
import com.qmth.exam.reserve.service.AuthService;
import com.qmth.exam.reserve.service.StudentService;
import com.qmth.exam.reserve.service.UserService;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
@AuthorizationComponent
public class AuthServiceImpl implements AuthorizationService<LoginUser>, AuthService {

    private final static Logger log = LoggerFactory.getLogger(AuthServiceImpl.class);

    @Autowired
    private LoginSessionManager loginSessionManager;

    @Autowired
    private UserService userService;

    @Autowired
    private StudentService studentService;

    @Autowired
    private ApplyTaskService applyTaskService;

    @Autowired
    private ApplyTaskCacheService applyTaskCacheService;

    @Autowired
    private OrgCacheService orgCacheService;

    @Override
    public LoginUser userLogin(LoginReq req) {
        if (StringUtils.isBlank(req.getAccount())) {
            throw new StatusException("登录账号不能为空");
        }

        if (StringUtils.isBlank(req.getPassword())) {
            throw new StatusException("登录密码不能为空");
        }

        if (req.getOrgId() == null) {
            OrgInfo org = orgCacheService.currentOrg();
            if (org != null) {
                req.setOrgId(org.getOrgId());
            }
        }

        log.info("[USER_LOGIN] verifying... account:{} orgId:{}", req.getAccount(), req.getOrgId());
        UserEntity user = userService.findUserByLoginName(req.getOrgId(), req.getAccount());
        if (user == null) {
            throw new StatusException("登录账号或密码错误");
        }

        String encodePassword = DigestUtils.sha256Hex(req.getPassword()).toUpperCase();
        if (!encodePassword.equals(user.getPassword())) {
            throw new StatusException("登录账号或密码错误");
        }

        LoginUser loginUser = new LoginUser();
        loginUser.setId(user.getId());
        loginUser.setAccount(user.getLoginName());
        loginUser.setName(user.getName());
        loginUser.setRole(user.getRole());
        loginUser.setOrgId(user.getOrgId());
        loginUser.setCategoryId(user.getCategoryId());

        loginUser.setSessionId(LoginSessionManager.USER_LOGIN + user.getId());
        loginUser.setToken(FastUUID.get());
        loginSessionManager.addLoginSession(loginUser);

        log.info("[USER_LOGIN] success! account:{} {} {}", loginUser.getAccount(), loginUser.getName(), loginUser.getRole());
        return loginUser;
    }

    @Override
    public LoginUser studentLogin(LoginReq req) {
        if (StringUtils.isBlank(req.getAccount())) {
            throw new StatusException("登录账号不能为空");
        }

        if (StringUtils.isBlank(req.getPassword())) {
            throw new StatusException("登录密码不能为空");
        }

        if (req.getOrgId() == null) {
            OrgInfo org = orgCacheService.currentOrg();
            if (org != null) {
                req.setOrgId(org.getOrgId());
            }
        }

        CurrentApplyTaskVO curApplyTask = applyTaskCacheService.currentApplyTask(req.getOrgId());
        if (curApplyTask == null) {
            throw new StatusException("尚未开启预约任务");
        }

        log.info("[STUDENT_LOGIN] verifying... account:{} orgId:{}", req.getAccount(), req.getOrgId());
        StudentEntity student = studentService.findByStudentCode(curApplyTask.getTaskId(), req.getAccount());
        if (student == null) {
            throw new StatusException("登录账号或密码错误");
        }

        String encodePassword = DigestUtils.sha256Hex(req.getPassword()).toUpperCase();
        if (!encodePassword.equals(student.getPassword())) {
            throw new StatusException("登录账号或密码错误");
        }

        LoginUser loginUser = new LoginUser();
        loginUser.setId(student.getId());
        loginUser.setAccount(student.getStudentCode());
        loginUser.setName(student.getName());
        loginUser.setRole(Role.STUDENT);
        loginUser.setOrgId(student.getOrgId());
        loginUser.setCategoryId(student.getCategoryId());
        loginUser.setApplyTaskId(student.getApplyTaskId());
        loginUser.setOpenId(student.getOpenId());

        loginUser.setSessionId(LoginSessionManager.STUDENT_LOGIN + student.getId());
        loginUser.setToken(FastUUID.get());
        loginSessionManager.addLoginSession(loginUser);

        log.info("[STUDENT_LOGIN] success! account:{} {}", loginUser.getAccount(), loginUser.getName());
        return loginUser;
    }

    @Override
    public LoginUser wechatLogin(WechatLoginReq req) {
        if (StringUtils.isBlank(req.getOpenId())) {
            throw new StatusException("微信OID不能为空");
        }

        log.info("[WECHAT_LOGIN] verifying... openId:{} uid:{}", req.getOpenId(), req.getUid());
        StudentEntity student = studentService.findByOpenIdAndUid(req.getOpenId(), req.getUid());
        if (student == null) {
            throw new StatusException("尚未绑定微信账号");
        }

        ApplyTaskEntity curApplyTask = applyTaskService.getLessInfoApplyTaskById(student.getApplyTaskId());
        if (curApplyTask == null || !curApplyTask.getEnable()) {
            throw new StatusException("尚未开启预约任务");
        }

        LoginUser loginUser = new LoginUser();
        loginUser.setId(student.getId());
        loginUser.setAccount(student.getStudentCode());
        loginUser.setName(student.getName());
        loginUser.setRole(Role.STUDENT);
        loginUser.setOrgId(student.getOrgId());
        loginUser.setCategoryId(student.getCategoryId());
        loginUser.setApplyTaskId(student.getApplyTaskId());
        loginUser.setOpenId(student.getOpenId());

        loginUser.setSessionId(LoginSessionManager.STUDENT_LOGIN + student.getId());
        loginUser.setToken(FastUUID.get());
        loginSessionManager.addLoginSession(loginUser);

        log.info("[WECHAT_LOGIN] success! account:{} {} {}", loginUser.getAccount(), loginUser.getName(), req.getOpenId());
        return loginUser;
    }

    @Override
    public void logout(LoginUser loginUser) {
        loginSessionManager.removeLoginSession(loginUser.getSessionId());
        log.warn("[LOGOUT] account:{} {}", loginUser.getAccount(), loginUser.getName());
    }

    @Override
    public LoginUser findByIdentity(String identity, SignatureType type, String path) {
        return loginSessionManager.getLoginSession(identity);
    }

}
