package lingtao.net.controller;

import lingtao.net.bean.Msg;
import lingtao.net.bean.SysRole;
import lingtao.net.bean.SysUser;
import lingtao.net.dao.SysUserMapper;
import lingtao.net.service.SysRoleService;
import lingtao.net.service.SysUserService;
import lingtao.net.util.MD5Util;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
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.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 用户登录注册、退出
 *
 * @author Administrator
 */
@Controller
@RequestMapping("/SysUser")
public class AcountController {

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private SysRoleService sysRoleService;

    @Autowired
    private SysUserMapper userMapper;

    /**
     * 获取客户端IP
     *
     * @param request 请求对象
     * @return IP地址
     */
    public static String getIpAddr(HttpServletRequest request) {
        if (request == null) {
            return "unknown";
        }
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Forwarded-For");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }

        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip);
    }

    /**
     * 从多级反向代理中获得第一个非unknown IP地址
     *
     * @param ip 获得的IP地址
     * @return 第一个非unknown IP地址
     */
    public static String getMultistageReverseProxyIp(String ip) {
        // 多级反向代理检测
        if (ip != null && ip.indexOf(",") > 0) {
            final String[] ips = ip.trim().split(",");
            for (String subIp : ips) {
                if (false == isUnknown(subIp)) {
                    ip = subIp;
                    break;
                }
            }
        }
        return StringUtils.substring(ip, 0, 255);
    }

    /**
     * 检测给定字符串是否为未知，多用于检测HTTP请求相关
     *
     * @param checkString 被检测的字符串
     * @return 是否未知
     */
    public static boolean isUnknown(String checkString) {
        return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
    }

    /**
     * 登陆
     */
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public ModelAndView login(@RequestParam("username") String username, @RequestParam("password") String password,
                              HttpServletRequest request, HttpServletResponse response) throws Exception {
        password = new MD5Util().md5(password, "lingtao");
        // 使用 shiro 登录验证
        // 1 认证的核心组件：获取 Subject 对象
        Subject subject = SecurityUtils.getSubject();
        // 2 将登陆表单封装成 token 对象
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        token.setHost(getIpAddr(request));
        try {
            // 3 让 shiro 框架进行登录验证：传递token给shiro的reaml
            subject.login(token);
            // return "redirect:/views/main.jsp";
            // 此处并没有跳转页面-前端根据状态码跳转对应页面
            return new ModelAndView("redirect:/views/main.jsp");
        } catch (UnknownAccountException uae) {
            // 状态码 200--成功 100--失败 300禁用
            response.getWriter().print("100");
            throw new UnknownAccountException("账户或密码有误！");
        } catch (IncorrectCredentialsException ice) {
            response.getWriter().print("100");
            throw new IncorrectCredentialsException("账户或密码有误！");
        } catch (LockedAccountException lae) {
            response.getWriter().print("300");
            throw new LockedAccountException("用户未激活！！！");
        } catch (AuthenticationException re) {
            response.getWriter().print("404");
            throw new AuthenticationException("未知IP！！！");
        }
        /* catch (RuntimeException re) { response.getWriter().print("400"); throw new
         * RuntimeException("用户已登录！！！"); }
         */

    }

    /**
     * 注册
     */
    @RequestMapping("/register")
    @ResponseBody
    public Msg register(SysUser user) {
        SysUser username = userMapper.getUserByUsername(user.getUsername());
        if (username != null) {
            return Msg.fail("用户名已存在！");
        }
        return sysUserService.register(user);
    }

    /**
     * 注销
     */
    @RequestMapping("/logout")
    public String logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return "redirect:/login.jsp";
    }

    /**
     * 获取可以被注册的角色名称
     *
     * @return
     */
    @RequestMapping("/getRoleName")
    @ResponseBody
    public Map<Number, String> roleNameList(@RequestParam(value = "isRegist") String isRegist) {
        Map<Number, String> map = new HashMap<Number, String>();
        List<SysRole> allRoleNames = sysRoleService.getAllRoleName(isRegist);

        for (SysRole sysRole : allRoleNames) {
            map.put(sysRole.getRoleId(), sysRole.getRoleName());
        }

        return map;
    }

    @ResponseBody
    @RequestMapping("/getIp")
    public Msg getIp(HttpServletRequest request) {
        String ip = getIpAddr(request);
//		String ip = "120.38.127.157";
        if (ip != null) {
            return Msg.success().add("ip", ip);
        }
        return Msg.fail();
    }
}
