package com.om.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.om.constant.RedisConstant;
import com.om.entity.dto.AdminAddDTO;
import com.om.entity.dto.AdminQueryPageDTO;
import com.om.entity.po.Admin;
import com.om.entity.po.User;
import com.om.entity.vo.AdminLoginVO;
import com.om.entity.vo.AdminQueryPageVO;
import com.om.exception.BadReqException;
import com.om.exception.BizException;
import com.om.mapper.AdminMapper;
import com.om.service.IAdminService;
import com.om.utils.AdminContext;
import com.om.utils.JwtUtils;
import com.om.utils.Result;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;

import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author bmmx
 * @since 2024-01-26
 */
@Service
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements IAdminService {

    @Resource
    private JwtUtils jwtUtils;

    @Resource
    private RedisTemplate redisTemplate;


    @Override
    public Result<AdminLoginVO> login(String username, String password) {
        if (StringUtils.isBlank(username)){
            throw new BadReqException("用户名不能为空！");
        }
        if (StringUtils.isBlank(password)){
            throw new BadReqException("密码不能为空！");
        }

        //根据username 查询数据库
        Admin admin = this.lambdaQuery()
                .eq(Admin::getUsername, username)
                .one();
        //判断是否存在
        if (BeanUtil.isEmpty(admin)){
            throw new BadReqException("该管理员不存在！请检查用户名是否正确！");
        }
        //密码加密
         password = DigestUtils.md5DigestAsHex(password.getBytes());
        //判断密码是否正确
        if (!StringUtils.equals(password,admin.getPassword())){
            throw new BizException("密码不正确，请检查用户名和密码是否正确！");
        }

        //判断管理员状态
        if (!admin.getEnabled()){
            throw new BadReqException("该管理员已被禁用！请联系系统管理员!!!");
        }
        //封装vo返回
        AdminLoginVO adminLoginVO = BeanUtil.copyProperties(admin, AdminLoginVO.class);
        //生成token
        Map<String, Object> claims = new HashMap<>();
        claims.put("a_id",admin.getId());
        String token = jwtUtils.generateToken(claims);
        //把token存入到redis中
        String key = RedisConstant.ADMIN_TOKEN_PREFIX + admin.getId();
        redisTemplate.opsForValue().set(key,token,RedisConstant.ADMIN_TOKEN_TTL, TimeUnit.SECONDS);
        adminLoginVO.setLoginToken(token);

        return Result.ok(adminLoginVO);
    }

    @Override
    public Result<AdminLoginVO> getManagerByToken(String token) {
        //根据token获取管理员id
        Integer adminId = jwtUtils.getAdminIdFromToken(token);

        //根据id查询管理员信息
        Admin admin = this.getById(adminId);
        //判断是否为空
        if (BeanUtil.isEmpty(admin)){
            throw new BadReqException("该管理员不存在，请重试！");
        }

        AdminLoginVO adminLoginVO = BeanUtil.copyProperties(admin, AdminLoginVO.class);
        adminLoginVO.setLoginToken(token);

        return Result.ok(adminLoginVO);
    }

    @Override
    public Result add(AdminAddDTO dto) {
        //获取当前登录管理员id
        Integer adminId = AdminContext.getAdminId();
        String username = dto.getUsername();
        String password = dto.getPassword();
        //判断dto中的数据是否为空
        if(StringUtils.isEmpty(username)){
            throw new BadReqException("管理员用户名为空");
        }
        if(StringUtils.isEmpty(password)){
            throw new BadReqException("管理员密码为空");
        }
        //判断dto中的用户名是否存在
        Admin one = this.lambdaQuery()
                .eq(Admin::getUsername, username)
                .one();
        if (!BeanUtil.isEmpty(one)){
            throw new BadReqException("该用户已经存在，请检查用户名");
        }

        LocalDateTime now = LocalDateTime.now();
        //密码加密
        password = DigestUtils.md5DigestAsHex(password.getBytes());
        Admin admin = BeanUtil.copyProperties(dto, Admin.class);
        admin.setPassword(password);
        admin.setOperatorId(adminId);
        admin.setCreateTime(now);
        admin.setUpdateTime(now);
        //保存到数据库
        this.save(admin);

        return Result.ok();
    }

    @Override
    public Result delete(Integer id) {
        //根据id查询管理员
        Admin admin = this.getById(id);
        //判断该管理员是否存在
        if (BeanUtil.isEmpty(admin)){
            throw new BadReqException("该管理员不存在");
        }
        //删除该管理员
        this.removeById(id);
        return Result.ok();
    }

    @Override
    public Result<AdminLoginVO> get(Integer id) {
        //根据id查询管理员
        Admin admin = this.getById(id);
        //判断该管理员是否存在
        if (BeanUtil.isEmpty(admin)){
            throw new BadReqException("该管理员不存在");
        }
        AdminLoginVO adminLoginVO = BeanUtil.copyProperties(admin, AdminLoginVO.class);

        //从redis中获取token
        String tokenKey = RedisConstant.ADMIN_TOKEN_PREFIX +id;
        String redisToken = (String) redisTemplate.opsForValue().get(tokenKey);
        adminLoginVO.setLoginToken(redisToken);


        return Result.ok(adminLoginVO);
    }

    @Override
    public Result<AdminLoginVO> updateAdmin(AdminAddDTO dto) {
        //获取当前登录管理员id
        Integer adminId = AdminContext.getAdminId();
        String username = dto.getUsername();
        String password = dto.getPassword();
        //判断dto中的数据是否为空
        if(StringUtils.isEmpty(username)){
            throw new BadReqException("管理员用户名为空");
        }
        //判断dto中的用户名是否存在
        Admin one = this.lambdaQuery()
                .eq(Admin::getUsername, username)
                .one();
        if (BeanUtil.isEmpty(one)){
            throw new BadReqException("该用户不存在，请检查用户名");
        }

        LocalDateTime now = LocalDateTime.now();
        //密码加密
        //如果密码密码为空则 不修改密码  使用原密码
        if (StringUtils.isEmpty(password)){
            password = one.getPassword();
        }else {
            password = DigestUtils.md5DigestAsHex(password.getBytes());
        }
        Admin admin = BeanUtil.copyProperties(dto, Admin.class);
        admin.setPassword(password);
        admin.setOperatorId(adminId);
        admin.setUpdateTime(now);
        //更新到数据库
        this.updateById(admin);

        //封装vo
        AdminLoginVO adminLoginVO = BeanUtil.copyProperties(admin, AdminLoginVO.class);
        //从redis中获取token
        String tokenKey = RedisConstant.ADMIN_TOKEN_PREFIX +adminId;
        String redisToken = (String) redisTemplate.opsForValue().get(tokenKey);
        adminLoginVO.setLoginToken(redisToken);

        return Result.ok(adminLoginVO);
    }

    @Override
    public Result updateState(Integer id) {
        //根据id查询管理员
        Admin admin = this.getById(id);
        //判断该管理员是否存在
        if (BeanUtil.isEmpty(admin)){
            throw new BadReqException("该管理员不存在");
        }

        admin.setEnabled(!admin.getEnabled());
        this.updateById(admin);
        return Result.ok();
    }

    @Override
    public Result logout(Integer id) {
        //把redis中的token删除
        //从redis中获取token
        String tokenKey = RedisConstant.ADMIN_TOKEN_PREFIX +id;
        if (!redisTemplate.hasKey(tokenKey)) {
            throw new BadReqException("该管理员的token不存在");
        }
        redisTemplate.delete(tokenKey);

        return Result.ok();
    }

    @Override
    public Result<AdminQueryPageVO> getPageList(AdminQueryPageDTO dto) {
        //获取dto中的数据
        Integer pageIndex = dto.getPageIndex();
        Integer pageSize = dto.getPageSize();
        //分页查询
        Page<Admin> page = this.lambdaQuery()
                .like(dto.getSearch() != null, Admin::getUsername, dto.getSearch())
                .orderByDesc(Admin::getCreateTime)
                .page(new Page<>(pageIndex, pageSize));


        AdminQueryPageVO adminQueryPageVO = new AdminQueryPageVO();
        adminQueryPageVO.setCurrent((int) page.getCurrent());
        adminQueryPageVO.setSize(pageSize);
        adminQueryPageVO.setPages((int) page.getPages());
        if (dto.getSearch() != null){
            adminQueryPageVO.setSearchCount(true);
        }

        List<Admin> records = page.getRecords();
        List<AdminLoginVO> list = new ArrayList<>();
        for (Admin record : records) {
            AdminLoginVO adminLoginVO = BeanUtil.copyProperties(record, AdminLoginVO.class);

            list.add(adminLoginVO);
        }

        adminQueryPageVO.setRecords(list);
        adminQueryPageVO.setTotal((int) page.getTotal());

        return Result.ok(adminQueryPageVO);
    }


}
