package rd.controller.user;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.crypto.digest.BCrypt;
import lombok.extern.slf4j.Slf4j;
import rd.data.code.ServiceCode;
import rd.data.db.table.UserBasic;
import rd.data.enums.UserType;
import rd.data.model.request.auth.UserLoginRequest;
import rd.data.model.response.Response;

import rd.data.model.response.auth.UserLoginStatusResponse;
import rd.data.model.response.user.UserBasicInfo;
import rd.service.user.StudentUserService;
import rd.service.user.UserBasicService;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * 登录认证Controller
 */
@Slf4j
@RestController
@RequestMapping("/user/auth")
public class UserAuthController {

    private final UserBasicService userBasicService;
    private final StudentUserService studentUserService;

    public UserAuthController(UserBasicService userBasicService, StudentUserService studentUserService) {
        this.userBasicService = userBasicService;
        this.studentUserService = studentUserService;
    }

    @RequestMapping("/login")
    public Response<UserBasicInfo> login(@RequestBody UserLoginRequest loginRequest) {
        String username = loginRequest.username();
        String password = loginRequest.password();

        UserBasic userBasic = userBasicService.getUserBasicByUsername(username);
        if (userBasic == null || userBasic.getPassword() == null || userBasic.getPassword().isEmpty()) {
            // 用户不存在，尝试从教务处获取用户信息
            log.info("用户'{}'不存在，尝试从教务处获取用户信息", username);
            try {
                var newStudentDto = studentUserService.tryAddStudentFromOfficial(username, password);
                userBasic = newStudentDto.userBasic();
            } catch (Exception e) {
                return Response.error(ServiceCode.StuNumDoesNotExists,
                        "从教务处获取用户信息失败，\n" +
                                "如果是非学生学生用户，请检查用户名是否正确；\n" +
                                "如果是学生用户，请检查用户名和密码，或者再重试重试一下。\nException：" + e
                );
            }
        } else {
            // 用户已经存在，直接从数据库获取数据
            if (!BCrypt.checkpw(password, userBasic.getPassword())) {
                return Response.error(ServiceCode.UserPasswordWrong);
            }
        }

        StpUtil.login(userBasic.getId());

        UserType userType = switch (userBasic.getType()) {
            case 0 -> UserType.STUDENT;
            case 1 -> UserType.TEACHER;
            case 2 -> UserType.ADMIN;
            default -> {
                log.warn("未知的用户类型：{}", userBasic.getType());
                yield UserType.STUDENT;
            }
        };

        var basicInfoResponse = UserBasicInfo.builder()
                .id(userBasic.getId())
                .username(userBasic.getUsername())
                .userType(userType)
                .build();

        return Response.success(basicInfoResponse);
    }

    @RequestMapping("/logout")
    public Response<String> logout() {
        StpUtil.logout();
        return Response.success();
    }

    @RequestMapping("/check")
    public Response<UserLoginStatusResponse> checkLogin() {
        boolean login = StpUtil.isLogin();
        if (!login) {
            return Response.success(new UserLoginStatusResponse(null, null, false));
        }

        Long uid = StpUtil.getLoginIdAsLong();
        String role = StpUtil.getRoleList().get(0);

        return Response.success(new UserLoginStatusResponse(uid, role, true));
    }

    @SaCheckLogin
    @RequestMapping("/modify-password")
    public Response<Object> modifyPassword(@RequestParam("old") String oldPassword,
                                           @RequestParam("new") String newPassword) {
        Long uid = StpUtil.getLoginIdAsLong();
        var userBasic = userBasicService.getUserBasicById(uid);
        if (!BCrypt.checkpw(oldPassword, userBasic.getPassword())) {
            return Response.error(ServiceCode.UserPasswordWrong);
        }

        userBasicService.updatePassword(uid, newPassword);

        StpUtil.logout();

        return Response.success();
    }
}
