package com.app.service.platform.auth;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import cn.hutool.core.util.IdUtil;
import com.app.constant.RedisKeyConstant;
import com.app.controller.platform.request.WebAdminAccountLoginDto;
import com.app.controller.platform.response.AccountInfoResponse;
import com.app.controller.platform.response.ImgCodeDto;
import com.app.controller.platform.response.LoginResponse;
import com.app.dto.Result;
import com.app.entity.platform.system.Account;
import com.app.entity.platform.system.AccountAuths;
import com.app.service.platform.dto.AccountDto;
import com.app.service.platform.monitor.OperationLogService;
import com.app.util.JwtUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Optional;
import java.util.concurrent.TimeUnit;


/**
 * 功能描述：
 *
 * @Author 梁展鹏
 */
@RequiredArgsConstructor
@Service
public class AuthenticationWebAdminService {

    @Value("${spring.profiles.active}")
    private String active;

    @Autowired
    private AccountService accountService;

    @Autowired
    private AccountAuthsService accountAuthsService;

    @Autowired
    private OnlineAccountService onlineAccountService;

    @Autowired
    private OperationLogService operationLogService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 功能描述：生成验证码
     *
     * @return
     */
    public Result<ImgCodeDto> imgCode() {
        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(130, 48, 4, 20);
        String verCode = captcha.getCode().toLowerCase();
        String uuid = IdUtil.simpleUUID();

        // 存入redis并设置过期时间为30分钟
        stringRedisTemplate.opsForValue().set(RedisKeyConstant.PlatformLoginImgCode(uuid), verCode, 60, TimeUnit.SECONDS);

        // 将key和base64返回给前端
        ImgCodeDto dto = new ImgCodeDto();
        String newBase = captcha.getImageBase64Data().replace("BASE64", "base64");
        dto.setBase64Img(newBase);
        dto.setUuid(uuid);

        return new Result().ok().setData(dto);
    }

    public Result<LoginResponse> login(WebAdminAccountLoginDto dto, HttpServletRequest request) {
        /* 校验图片验证码 */
        checkImgCode(dto.getUuid(), dto.getCode());

        Account _account = checkAccount(dto.getUsername(), dto.getPassword());

        /* 生成访问令牌 */
        String token = JwtUtil.createTokenByPlatform(_account.getId());
        String refreshToken = "";

        /* 保存在线账号 */
        onlineAccountService.goOnline(_account, request, token, refreshToken);
        operationLogService.insertLoginLog(request, _account.getNickname(), "管理后台登录");

        /* 一个账号只能同时登录一个地方(dev环境暂不约束) */
        if (!"dev".equals(active)) {
            onlineAccountService.checkLogin(_account, token);
        }

        LoginResponse _loginResponse = new LoginResponse();
        _loginResponse.setToken(token);
        _loginResponse.setRefreshToken("");
        return new Result().ok().setData(_loginResponse);
    }

    private void checkImgCode(String uuid, String code) {
        /* 校验验证码是否有效 */
        String verCode = stringRedisTemplate.opsForValue().get(RedisKeyConstant.PlatformLoginImgCode(uuid));
        if (StringUtils.isEmpty(verCode)) {
            throw new RuntimeException("验证码不存在或已过期");
        }
        if (!verCode.equalsIgnoreCase(code.trim())) {
            throw new RuntimeException("验证码错误");
        }

        /* 验证码通过后才手动删除 */
        stringRedisTemplate.delete(RedisKeyConstant.PlatformLoginImgCode(uuid));
    }

    private Account checkAccount(String username, String password) {
        Optional<AccountAuths> optional = accountAuthsService.findByUsername(username);
        if (!optional.isPresent()) {
            throw new RuntimeException("不存在该用户!");
        }
        Account _account = accountService.findById(optional.get().getAccountId()).get();

        if (_account.getIsDel()) {
            throw new RuntimeException("该账户已被禁用，请联系管理员");
        } else if (_account.getIsLocked()) {
            throw new RuntimeException("该账号已被锁定");
        } else if (null != _account.getEndDateTime() && _account.getEndDateTime().isAfter(LocalDateTime.now())) {
            throw new RuntimeException("该账号已过期，请联系管理员");
        }

        /* 验证密码 */
        String dbPassword = optional.get().getCredential();
        if (!dbPassword.equals(password)) {
            throw new RuntimeException("密码或账号错误");
        }

        return _account;
    }

    public Result<AccountInfoResponse> info() {
        AccountDto accountDto = accountService.findCacheById(JwtUtil.getLocalUser().get().getId());
        AccountInfoResponse _accountInfoResponse = new AccountInfoResponse();
        _accountInfoResponse.setNickname(accountDto.getNickname());
        _accountInfoResponse.setAvatar(accountDto.getAvatarUrl());
        _accountInfoResponse.setIntroduction("这是简介");
        _accountInfoResponse.setRoles(new ArrayList<String>() {{
            add("admin");
            add("editor");
        }});

        return new Result().ok().setData(_accountInfoResponse);
    }

    public void logout() {
        AccountDto accountDto = accountService.findCacheById(JwtUtil.getLocalUser().get().getId());
        if (Optional.ofNullable(accountDto).isPresent()) {
            onlineAccountService.logout(accountDto.getId());
        }
    }

}
