package com.snack.server.module.admin.service;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.snack.server.common.ResultCode;
import com.snack.server.module.admin.dto.req.AdminLoginReq;
import com.snack.server.module.admin.dto.req.AdminPageReq;
import com.snack.server.module.admin.dto.req.AdminProfileReq;
import com.snack.server.module.admin.dto.req.AdminSaveReq;
import com.snack.server.module.admin.dto.req.ChangePasswordReq;
import com.snack.server.module.admin.entity.Admin;
import com.snack.server.exception.BusinessException;
import com.snack.server.module.admin.mapper.AdminMapper;
import com.snack.server.module.admin.service.AdminService;
import com.snack.server.module.admin.vo.AdminVO;
import com.snack.server.module.admin.vo.LoginVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

/**
 * 管理员业务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AdminServiceImpl implements AdminService {

    private final AdminMapper adminMapper;
    private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    // ==================== 登录相关 ====================

    @Override
    @Transactional(rollbackFor = Exception.class)
    public LoginVO login(AdminLoginReq req, String clientIp) {
        // 1. 查询管理员
        Admin admin = adminMapper.selectOne(
                new LambdaQueryWrapper<Admin>().eq(Admin::getUsername, req.getUsername())
        );
        if (admin == null) {
            throw new BusinessException(ResultCode.PASSWORD_ERROR); // 不暴露用户名是否存在
        }

        // 2. 校验状态
        if (admin.getStatus() != null && admin.getStatus() == 0) {
            throw new BusinessException(ResultCode.USER_DISABLED);
        }

        // 3. 校验密码（BCrypt 校验）
        if (!passwordEncoder.matches(req.getPassword(), admin.getPassword())) {
            throw new BusinessException(ResultCode.PASSWORD_ERROR);
        }

        // 4. Sa-Token 登录
        StpUtil.login(admin.getId());
        String token = StpUtil.getTokenValue();

        // 5. 更新登录信息（异步优化：可改为线程池执行）
        updateLoginInfo(admin.getId(), clientIp);

        // 6. 构造返回
        LoginVO vo = new LoginVO();
        vo.setToken(token);
        vo.setExpiresIn(StpUtil.getTokenTimeout());
        vo.setAdminInfo(toVO(admin));
        return vo;
    }

    @Override
    public void logout() {
        if (StpUtil.isLogin()) {
            StpUtil.logout();
        }
    }

    @Override
    public void updateLoginInfo(Long id, String clientIp) {
        Admin update = new Admin();
        update.setId(id);
        update.setLastLoginTime(LocalDateTime.now());
        update.setLastLoginIp(clientIp);
        adminMapper.updateById(update);
    }

    // ==================== 当前登录管理员 ====================

    @Override
    public AdminVO getCurrentAdmin() {
        Long id = StpUtil.getLoginIdAsLong();
        Admin admin = adminMapper.selectById(id);
        if (admin == null) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }
        return toVO(admin);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateProfile(AdminProfileReq req) {
        Long id = StpUtil.getLoginIdAsLong();
        Admin admin = adminMapper.selectById(id);
        if (admin == null) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }
        Admin update = new Admin();
        update.setId(id);
        update.setNickname(req.getNickname());
        update.setAvatar(req.getAvatar());
        update.setEmail(req.getEmail());
        update.setPhone(req.getPhone());
        adminMapper.updateById(update);
        log.info("管理员 id={} 更新个人资料", id);
    }

    // ==================== 列表 / 详情 ====================

    @Override
    public Page<AdminVO> pageAdmins(AdminPageReq req) {
        Page<Admin> page = new Page<>(req.getCurrent(), req.getSize());
        LambdaQueryWrapper<Admin> wrapper = new LambdaQueryWrapper<Admin>()
                // 关键字模糊搜索
                .and(StrUtil.isNotBlank(req.getKeyword()), w -> w
                        .like(Admin::getUsername, req.getKeyword())
                        .or().like(Admin::getNickname, req.getKeyword())
                        .or().like(Admin::getPhone, req.getKeyword())
                )
                .eq(StrUtil.isNotBlank(req.getRole()), Admin::getRole, req.getRole())
                .eq(req.getStatus() != null, Admin::getStatus, req.getStatus())
                .orderByDesc(Admin::getId);

        Page<Admin> result = adminMapper.selectPage(page, wrapper);
        Page<AdminVO> voPage = new Page<>(result.getCurrent(), result.getSize(), result.getTotal());
        voPage.setRecords(result.getRecords().stream().map(this::toVO).toList());
        return voPage;
    }

    @Override
    public AdminVO getAdminById(Long id) {
        Admin admin = adminMapper.selectById(id);
        if (admin == null) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }
        return toVO(admin);
    }

    // ==================== 创建 / 更新 / 删除 ====================

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createAdmin(AdminSaveReq req) {
        // 1. 用户名唯一性校验
        long count = adminMapper.selectCount(
                new LambdaQueryWrapper<Admin>().eq(Admin::getUsername, req.getUsername())
        );
        if (count > 0) {
            throw new BusinessException(1003, "用户名已存在");
        }

        // 2. 密码必填
        if (StrUtil.isBlank(req.getPassword())) {
            throw new BusinessException(1000, "密码不能为空");
        }

        // 3. 入库
        Admin admin = new Admin();
        BeanUtil.copyProperties(req, admin, "id");
        admin.setPassword(passwordEncoder.encode(req.getPassword()));
        admin.setStatus(req.getStatus() == null ? 1 : req.getStatus());
        adminMapper.insert(admin);
        log.info("创建管理员成功 id={} username={}", admin.getId(), admin.getUsername());
        return admin.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAdmin(AdminSaveReq req) {
        if (req.getId() == null) {
            throw new BusinessException(1000, "ID 不能为空");
        }
        Admin existing = adminMapper.selectById(req.getId());
        if (existing == null) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }

        // 用户名查重（排除自己）
        long count = adminMapper.selectCount(
                new LambdaQueryWrapper<Admin>()
                        .eq(Admin::getUsername, req.getUsername())
                        .ne(Admin::getId, req.getId())
        );
        if (count > 0) {
            throw new BusinessException(1003, "用户名已存在");
        }

        // 不修改密码
        Admin admin = new Admin();
        BeanUtil.copyProperties(req, admin, "password");
        adminMapper.updateById(admin);
        log.info("更新管理员成功 id={}", admin.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAdmin(Long id) {
        // 不允许删除自己
        if (StpUtil.getLoginIdAsLong() == id) {
            throw new BusinessException(1000, "不能删除自己");
        }
        // 不允许删除超级管理员
        Admin admin = adminMapper.selectById(id);
        if (admin == null) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }
        if ("super_admin".equals(admin.getRole())) {
            throw new BusinessException(1000, "不能删除超级管理员");
        }
        adminMapper.deleteById(id);
        log.info("删除管理员 id={}", id);
    }

    // ==================== 密码相关 ====================

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changePassword(ChangePasswordReq req) {
        Long id = StpUtil.getLoginIdAsLong();
        Admin admin = adminMapper.selectById(id);
        if (admin == null) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }
        if (!passwordEncoder.matches(req.getOldPassword(), admin.getPassword())) {
            throw new BusinessException(ResultCode.OLD_PASSWORD_ERROR);
        }
        if (req.getNewPassword().equals(req.getOldPassword())) {
            throw new BusinessException(1000, "新密码不能与原密码相同");
        }
        Admin update = new Admin();
        update.setId(id);
        update.setPassword(passwordEncoder.encode(req.getNewPassword()));
        adminMapper.updateById(update);
        log.info("管理员 id={} 修改密码成功", id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resetPassword(Long id, String newPassword) {
        if (StrUtil.isBlank(newPassword) || newPassword.length() < 6) {
            throw new BusinessException(1000, "新密码至少 6 位");
        }
        Admin admin = adminMapper.selectById(id);
        if (admin == null) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }
        Admin update = new Admin();
        update.setId(id);
        update.setPassword(passwordEncoder.encode(newPassword));
        adminMapper.updateById(update);
        log.info("重置管理员 id={} 密码", id);
    }

    // ==================== 状态切换 ====================

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStatus(Long id, Integer status) {
        if (id == null || status == null) {
            throw new BusinessException(1000, "参数错误");
        }
        if (StpUtil.getLoginIdAsLong() == id) {
            throw new BusinessException(1000, "不能禁用自己");
        }
        Admin admin = adminMapper.selectById(id);
        if (admin == null) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }
        if ("super_admin".equals(admin.getRole())) {
            throw new BusinessException(1000, "不能禁用超级管理员");
        }
        Admin update = new Admin();
        update.setId(id);
        update.setStatus(status);
        adminMapper.updateById(update);
        log.info("管理员 id={} 状态更新为 {}", id, status);
    }

    // ==================== 私有方法 ====================

    private AdminVO toVO(Admin admin) {
        AdminVO vo = new AdminVO();
        BeanUtil.copyProperties(admin, vo, "password");
        return vo;
    }
}
