package cn.hanghui.outapi.platform.common.service.impl;

import cn.hanghui.outapi.platform.common.config.JwtConfig;
import cn.hanghui.outapi.platform.common.entity.dto.LoginDto;
import cn.hanghui.outapi.platform.common.entity.po.Account;
import cn.hanghui.outapi.platform.common.entity.rest.RespCodeEnum;
import cn.hanghui.outapi.platform.common.exception.CommonException;
import cn.hanghui.outapi.platform.common.handler.LoginAuthorizedHandler;
import cn.hanghui.outapi.platform.common.mapper.AccountMapper;
import cn.hanghui.outapi.platform.common.service.LoginService;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.jwt.JWTUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
//@AllArgsConstructor(onConstructor_ = @Autowired)
public class LoginServiceImpl implements LoginService {

    @Resource
    @Lazy
    private AccountMapper accountMapper;

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
        String token = redisTemplate.opsForValue().get(JwtConfig.TOKEN_PREFIX + name.toLowerCase());
        Account account;
        if (ObjectUtil.isNotEmpty(token)) {
            String session = redisTemplate.opsForValue().get(JwtConfig.SESSION_PREFIX + token);
            account = JSON.parseObject(session, Account.class);
        } else {
            account = accountMapper.selectOne(Wrappers.lambdaQuery(Account.class).eq(Account::getName, name));
        }
        if (account == null) {
            throw new CommonException(RespCodeEnum.ACCOUNT_OR_PASSWORD_ERROR);
        }
        return User.builder().username(name).password(account.getPassword()).roles("caller").build();
    }

    /**
     * 登录
     *
     * @param loginDto LoginDto
     * @return token
     */
    @Override
    public String login(LoginDto loginDto) {
        LoginAuthorizedHandler loginAuthorizedHandler = SpringUtil.getBean(LoginAuthorizedHandler.class);
        loginAuthorizedHandler.authenticate(
                new UsernamePasswordAuthenticationToken(loginDto.getAccountName(), loginDto.getPassword())
        );
        Account account = accountMapper.selectOne(Wrappers.lambdaQuery(Account.class).eq(Account::getName, loginDto.getAccountName()));
        Account tokenAccount = new Account();
        tokenAccount.setName(loginDto.getAccountName());
        tokenAccount.setPassword(loginDto.getPassword());
        Map<String, Object> payload = BeanUtil.beanToMap(tokenAccount);
        String token = JWTUtil.createToken(payload, JwtConfig.SECRET_KEY.getBytes());
        redisTemplate.opsForValue().set(JwtConfig.TOKEN_PREFIX + loginDto.getAccountName().toLowerCase(), token, JwtConfig.EXPIRE_TIME, TimeUnit.SECONDS);
        redisTemplate.opsForValue().set(JwtConfig.SESSION_PREFIX + token, JSON.toJSONString(account), JwtConfig.EXPIRE_TIME, TimeUnit.SECONDS);
        return token;
    }
}
