package top.continew.admin.controller.auth;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import top.continew.admin.auth.model.req.AccountLoginReq;
import top.continew.admin.auth.model.req.EmailLoginReq;
import top.continew.admin.auth.model.req.EmailRegisterReq;
import top.continew.admin.auth.model.req.PhoneLoginReq;
import top.continew.admin.auth.model.req.PhoneRegisterReq;
import top.continew.admin.auth.model.req.UserRegisterReq;
import top.continew.admin.auth.model.resp.DeptInfo;
import top.continew.admin.auth.model.resp.LoginResp;
import top.continew.admin.auth.model.resp.RouteResp;
import top.continew.admin.auth.model.resp.UserInfoResp;
import top.continew.admin.auth.service.LoginService;
import top.continew.admin.business.service.PlantformBalanceService;
import top.continew.admin.common.constant.CacheConstants;
import top.continew.admin.common.model.dto.LoginUser;
import top.continew.admin.common.util.JwtUtil;
import top.continew.admin.common.util.SecureUtils;
import top.continew.admin.common.util.helper.LoginHelper;
import top.continew.admin.system.model.entity.DeptDO;
import top.continew.admin.system.model.resp.SimpleUserInfoResp;
import top.continew.admin.system.model.resp.UserDetailResp;
import top.continew.admin.system.service.DeptService;
import top.continew.admin.system.service.UserService;
import top.continew.starter.cache.redisson.util.RedisUtils;
import top.continew.starter.core.util.ExceptionUtils;
import top.continew.starter.core.util.validate.ValidationUtils;
import top.continew.starter.log.core.annotation.Log;
import top.continew.starter.web.model.R;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 认证 API
 *
 * @author Charles7c
 * @since 2022/12/21 20:37
 */
@Log(module = "登录")
@Tag(name = "认证 API")
@RestController
@RequiredArgsConstructor
@RequestMapping("/auth")
public class AuthController {

    private static final String CAPTCHA_EXPIRED = "验证码已失效";
    private static final String CAPTCHA_ERROR = "验证码错误";
    private final LoginService loginService;
    private final UserService userService;
    private final DeptService deptService;
    private final PlantformBalanceService plantformBalanceService;

    @SaIgnore
    @Operation(summary = "账号登录", description = "根据账号和密码进行登录认证")
    @PostMapping("/account")
    public LoginResp accountLogin(@Validated @RequestBody AccountLoginReq loginReq, HttpServletRequest request) {
        String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + loginReq.getUuid();
        String captcha = RedisUtils.get(captchaKey);
        ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
        ValidationUtils.throwIfNotEqualIgnoreCase(loginReq.getCaptcha(), captcha, CAPTCHA_ERROR);
        RedisUtils.delete(captchaKey);
        // 用户登录
        String rawPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(loginReq.getPassword()));
        ValidationUtils.throwIfBlank(rawPassword, "密码解密失败");
        LoginUser loginUser = loginService.accountLogin(loginReq.getUsername(), rawPassword, request);

        // 生成JWT Token
        String token = JwtUtil.generateToken(loginUser.getId().toString());
        System.out.println("Generated Token: " + token);

        // 从Token中获取用户名和其他信息（例如过期时间）
        String username = JwtUtil.getUsernameFromToken(token);
        Date expirationDate = JwtUtil.getExpirationDateFromToken(token);
        System.out.println("id: " + username);
        return LoginResp.builder()
            .generateToken(token)
            .token(loginUser.getToken())
            .aiBotToken(loginUser.getAiBotToken())
            .sdBotToken(loginUser.getSdBotToken())
            .build();
    }

    @SaIgnore
    @Operation(summary = "手机号登录", description = "根据手机号和验证码进行登录认证")
    @PostMapping("/phone")
    public LoginResp phoneLogin(@Validated @RequestBody PhoneLoginReq loginReq) {
        String phone = loginReq.getPhone();
        String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + phone;
        String captcha = RedisUtils.get(captchaKey);
        ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
        ValidationUtils.throwIfNotEqualIgnoreCase(loginReq.getCaptcha(), captcha, CAPTCHA_ERROR);
        RedisUtils.delete(captchaKey);
        LoginUser loginUser = loginService.phoneLogin(phone);
        return LoginResp.builder()
            .token(loginUser.getToken())
            .aiBotToken(loginUser.getAiBotToken())
            .sdBotToken(loginUser.getSdBotToken())
            .build();
    }

    @SaIgnore
    @Operation(summary = "邮箱登录", description = "根据邮箱和验证码进行登录认证")
    @PostMapping("/email")
    public LoginResp emailLogin(@Validated @RequestBody EmailLoginReq loginReq) {
        String email = loginReq.getEmail();
        String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + email;
        String captcha = RedisUtils.get(captchaKey);
        ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
        ValidationUtils.throwIfNotEqualIgnoreCase(loginReq.getCaptcha(), captcha, CAPTCHA_ERROR);
        RedisUtils.delete(captchaKey);
        LoginUser loginUser = loginService.emailLogin(email);
        return LoginResp.builder()
            .token(loginUser.getToken())
            .aiBotToken(loginUser.getAiBotToken())
            .sdBotToken(loginUser.getSdBotToken())
            .build();
    }

    @Operation(summary = "用户退出", description = "注销用户的当前登录")
    @Parameter(name = "Authorization", description = "令牌", required = true, example = "Bearer xxxx-xxxx-xxxx-xxxx", in = ParameterIn.HEADER)
    @PostMapping("/logout")
    public Object logout() {
        Object loginId = StpUtil.getLoginId(-1L);
        StpUtil.logout();
        return loginId;
    }

    @Log(ignore = true)
    @Operation(summary = "获取用户信息", description = "获取登录用户信息")
    @GetMapping("/user/info")
    public UserInfoResp getUserInfo() {
        LoginUser loginUser = LoginHelper.getLoginUser();
        UserDetailResp userDetailResp = userService.get(loginUser.getId());
        UserInfoResp userInfoResp = BeanUtil.copyProperties(userDetailResp, UserInfoResp.class);
        userInfoResp.setPermissions(loginUser.getPermissions());
        userInfoResp.setRoles(loginUser.getRoleCodes());
        userInfoResp.setPwdExpired(loginUser.isPasswordExpired());
        userInfoResp.setRouters(loginUser.getRouters());

        // 获取当前用户的部门ID
        Long deptId = userDetailResp.getDeptId();
        if (deptId != null) {
            // 根据用户ID查询所有相关部门（包括父部门和子部门）
            List<DeptInfo> deptInfoList = getRelatedDeptsByUserId(deptId);
            userInfoResp.setDeptInfos(deptInfoList.toArray(new DeptInfo[0]));
        }

        return userInfoResp;
    }

    /**
     * 根据用户部门ID获取所有相关部门（包括父部门和子部门）
     */
    private List<DeptInfo> getRelatedDeptsByUserId(Long deptId) {
        List<DeptInfo> deptInfoList = new ArrayList<>();

        // 获取用户所在部门及其所有父部门
        DeptDO currentDept = deptService.getById(deptId);
        if (currentDept != null) {
            // 添加当前部门
            DeptInfo currentDeptInfo = new DeptInfo();
            currentDeptInfo.setDeptId(currentDept.getId());
            currentDeptInfo.setName(currentDept.getName());
            deptInfoList.add(currentDeptInfo);

            // 添加父部门
            addParentDepts(currentDept.getParentId(), deptInfoList);

            /*// 获取并添加所有子部门
            List<DeptDO> allChildren = deptService.listChildren(deptId);
            for (DeptDO child : allChildren) {
                DeptInfo childDeptInfo = new DeptInfo();
                childDeptInfo.setDeptId(child.getId());
                childDeptInfo.setName(child.getName());
                deptInfoList.add(childDeptInfo);
            }*/
        }

        return deptInfoList;
    }

    /**
     * 递归添加所有父部门
     */
    private void addParentDepts(Long parentId, List<DeptInfo> deptInfoList) {
        if (parentId == null || parentId == 0) {
            return;
        }

        DeptDO parentDept = deptService.getById(parentId);
        if (parentDept != null) {
            DeptInfo parentDeptInfo = new DeptInfo();
            parentDeptInfo.setDeptId(parentDept.getId());
            parentDeptInfo.setName(parentDept.getName());
            deptInfoList.add(parentDeptInfo);

            // 递归添加上级部门
            addParentDepts(parentDept.getParentId(), deptInfoList);
        }
    }

    @Log(ignore = true)
    @Operation(summary = "验证token字符串", description = "验证token字符串")
    @GetMapping("/check/token/{token}")
    public boolean checkToken(@PathVariable String token) {
        try {
            Object loginIdByToken = StpUtil.getLoginIdByToken(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    @Log(ignore = true)
    @Operation(summary = "验证token字符串并返回用户信息", description = "验证token字符串并返回用户信息")
    @GetMapping("/check/checkTokenRn/{token}")
    public R checkTokenRn(@PathVariable String token) {
        try {
            Long loginIdByToken = Long.parseLong((String)StpUtil.getLoginIdByToken(token));
            UserDetailResp userDetailResp = userService.get(loginIdByToken);
            SimpleUserInfoResp simpleBeanInfo = BeanUtil.copyProperties(userDetailResp, SimpleUserInfoResp.class);
            return R.ok(simpleBeanInfo);
        } catch (Exception e) {
            return R.fail("token无效", e.getMessage());
        }
    }

    @Log(ignore = true)
    @Operation(summary = "验证token", description = "验证token")
    @GetMapping("/check/token")
    public String checkToken() {
        LoginUser loginUser = LoginHelper.getLoginUser();
        ValidationUtils.throwIfNull(loginUser, "token失效");
        //String token = JwtUtil.generateToken(loginUser.getId().toString());
        return loginUser.getId().toString();
    }

    @Log(ignore = true)
    @Operation(summary = "获取路由信息", description = "获取登录用户的路由信息")
    @GetMapping("/route")
    public List<RouteResp> listRoute() {
        return loginService.buildRouteTree(LoginHelper.getUserId());
    }

    @SaIgnore
    @Operation(summary = "用户名密码注册", description = "根据用户名、密码和验证码进行用户注册")
    @PostMapping("/register")
    public LoginResp userRegister(@Validated @RequestBody UserRegisterReq registerReq, HttpServletRequest request) {
        LoginUser loginUser = loginService.userRegister(registerReq, request);

        // 生成JWT Token
        String token = JwtUtil.generateToken(loginUser.getId().toString());

        //添加用户子账户
        //        for (int i = 0; i < ChargeTypeEnum.values().length; i++) {
        //            PlantformBalanceAddReq plantformBalanceAddReq = new PlantformBalanceAddReq().initPlantformBalance();
        //            plantformBalanceAddReq.setChargeType(ChargeTypeEnum.getType(i));
        //            plantformBalanceAddReq.setUserId(loginUser.getId());
        //            plantformBalanceService.addPlantformBalance(plantformBalanceAddReq);
        //        }

        return LoginResp.builder()
            .generateToken(token)
            .token(loginUser.getToken())
            .aiBotToken(loginUser.getAiBotToken())
            .sdBotToken(loginUser.getSdBotToken())
            .build();
    }

    @SaIgnore
    @Operation(summary = "手机号注册", description = "根据手机号、密码和验证码进行用户注册")
    @PostMapping("/register/phone")
    public LoginResp phoneRegister(@Validated @RequestBody PhoneRegisterReq registerReq, HttpServletRequest request) {
        LoginUser loginUser = loginService.phoneRegister(registerReq, request);

        // 生成JWT Token
        String token = JwtUtil.generateToken(loginUser.getId().toString());

        //添加用户子账户
        //        for (int i = 0; i < ChargeTypeEnum.values().length; i++) {
        //            PlantformBalanceAddReq plantformBalanceAddReq = new PlantformBalanceAddReq().initPlantformBalance();
        //            plantformBalanceAddReq.setChargeType(ChargeTypeEnum.getType(i));
        //            plantformBalanceAddReq.setUserId(loginUser.getId());
        //            plantformBalanceService.addPlantformBalance(plantformBalanceAddReq);
        //        }

        return LoginResp.builder()
            .generateToken(token)
            .token(loginUser.getToken())
            .aiBotToken(loginUser.getAiBotToken())
            .sdBotToken(loginUser.getSdBotToken())
            .build();
    }

    @SaIgnore
    @Operation(summary = "邮箱注册", description = "根据邮箱、密码和验证码进行用户注册")
    @PostMapping("/register/email")
    public LoginResp emailRegister(@Validated @RequestBody EmailRegisterReq registerReq, HttpServletRequest request) {
        LoginUser loginUser = loginService.emailRegister(registerReq, request);

        // 生成JWT Token
        String token = JwtUtil.generateToken(loginUser.getId().toString());

        return LoginResp.builder()
            .generateToken(token)
            .token(loginUser.getToken())
            .aiBotToken(loginUser.getAiBotToken())
            .sdBotToken(loginUser.getSdBotToken())
            .build();
    }
}
