package com.dtok.api.controller;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.crypto.SecureUtil;

import cn.hutool.db.nosql.redis.RedisDS;
import com.dtok.entity.Account;
import com.dtok.entity.AccountRole;
import com.dtok.entity.LoginHistory;
import com.dtok.entity.emum.LOGIN_DEVICE;
import com.dtok.entity.params.UserResponse;
import com.dtok.framework.exception.AuthenticateException;
import com.dtok.framework.exception.BizExceptionEnum;
import com.dtok.framework.exception.BusinessException;
import com.dtok.framework.exception.ServiceException;
import com.dtok.framework.response.ResponseData;
import com.dtok.framework.util.IpUtil;
import com.dtok.framework.util.RedisUtil;
import com.dtok.repository.AccountRepository;
import com.dtok.repository.AccountRoleRepository;
import com.dtok.repository.LoginHistoryRepository;
import com.dtok.service.PermissionService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import redis.clients.jedis.Jedis;

import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@Api(value = "登录", tags = {"登录"})
@Slf4j
public class LoginController {


    final
    AccountRepository userRepository;

    final
    LoginHistoryRepository loginHistoryRepository;

    final
    PermissionService permissionService;

    final
    AccountRoleRepository roleRepository;

    private static final Logger LOGIN_LOG = LoggerFactory.getLogger("LoginLog");


    public LoginController(AccountRepository userRepository, LoginHistoryRepository loginHistoryRepository, PermissionService permissionService, AccountRoleRepository roleRepository) {
        this.userRepository = userRepository;
        this.loginHistoryRepository = loginHistoryRepository;
        this.permissionService = permissionService;
        this.roleRepository = roleRepository;
    }


    @PostMapping("/login")
    @ResponseBody
    @ApiOperation("登录")
    public ResponseData login(String username, String password, String loginDevice) {
        // get user
        Account user = userRepository.getUserLoginEntity(username);


        if (Objects.isNull(user)) {
            throw new AuthenticateException(BizExceptionEnum.NO_THIS_USER);
        }

        if (!SaSecureUtil.aesEncrypt(user.getSalt(), password).equals(user.getPassword())) {
            throw new AuthenticateException(BizExceptionEnum.AUTH_REQUEST_ERROR);
        }

        if (!user.getStatus()) {
            throw new AuthenticateException(BizExceptionEnum.ACCOUNT_FREEZED);
        }

        if (user.getRoleCode().isEmpty()) {
            throw new AuthenticateException(BizExceptionEnum.NOT_ROLE_EXCEPTION);
        }

        if (!loginDevice.equals(LOGIN_DEVICE.DEVICE.getType()) && !loginDevice.equals(LOGIN_DEVICE.PC.getType())) {
            throw new AuthenticateException(BizExceptionEnum.NO_PERMISSION);
        }
        Timestamp timestamp = new Timestamp((new Date()).getTime());

        if (!Objects.isNull(user.getExpireAt()) && user.getExpireAt().before(timestamp)){
            throw new AuthenticateException(BizExceptionEnum.ACCOUNT_EXPIRE);
        }

        Optional<AccountRole> role = roleRepository.findById(user.getRoleCode());
        if (!role.isPresent()) {
            throw new AuthenticateException(BizExceptionEnum.ROLE_ERROR);
        }



        String token;

        token = StpUtil.getTokenValueByLoginId(username);
        //没有token执行登录
        if (!StringUtils.hasLength(token)) {
            StpUtil.login(username, loginDevice);
            token = StpUtil.getTokenValue();
            StpUtil.setTokenValue(token);
            StpUtil.getSession().set("loginUser", user);
        }

        if (loginDevice.equals(LOGIN_DEVICE.DEVICE.getType())){
            Map<String,Object> stringStringMap = new HashMap<>();
            stringStringMap.put("token",token);
            stringStringMap.put("user",user);
            return ResponseData.success(stringStringMap);
        }

        LOGIN_LOG.info(String.format("用户 %s 登录 ... token: %s", user.getName(), token));
        UserResponse userResponse = new UserResponse();
        userResponse.setUser(user);
        userResponse.setToken(token);
        userResponse.setRole(role.get());
        userResponse.setPermissions(permissionService.getTree(user.getUsername()));

        //记录登录日志
        LoginHistory loginHistory = new LoginHistory();
        loginHistory.setIp(IpUtil.getLocalhostIp());
        loginHistory.setUser(user.getId());
        loginHistory.setHappenTime(new DateTime());
        loginHistory.setActionType(1);
        loginHistory.setUsername(username);
        loginHistory.setLoginSys(loginDevice);
        loginHistoryRepository.save(loginHistory);
        return ResponseData.success(userResponse);
    }

    @GetMapping("/logout")
    public ResponseData logout(@RequestParam("loginDevice") String loginDevice) {
        if (!StringUtils.hasLength(loginDevice)) {
            throw new ServiceException(BizExceptionEnum.SERVER_ERROR);
        }

        if (!loginDevice.equals(LOGIN_DEVICE.DEVICE.getType()) && !loginDevice.equals(LOGIN_DEVICE.PC.getType())) {
            throw new AuthenticateException(BizExceptionEnum.NO_PERMISSION);
        }
        if (loginDevice.equals(LOGIN_DEVICE.PC.getType())){
            StpUtil.login(StpUtil.getLoginId(), LOGIN_DEVICE.PC.getType());
        }
        LoginHistory loginHistory = new LoginHistory();
        loginHistory.setIp(IpUtil.getLocalhostIp());
        loginHistory.setUser(((Account) StpUtil.getSession().get("loginUser")).getId());
        loginHistory.setHappenTime(new DateTime());
        loginHistory.setActionType(0);
        loginHistory.setUsername(((Account) StpUtil.getSession().get("loginUser")).getUsername());
        loginHistory.setLoginSys(loginDevice);
        loginHistoryRepository.save(loginHistory);
        return ResponseData.success("注销成功");
    }


}
