package cn.novalon.manage.sys.handler.user;

import cn.novalon.manage.sys.core.domain.SysUser;
import cn.novalon.manage.sys.core.service.ISysUserService;
import cn.novalon.manage.common.dto.PageRequest;
import cn.novalon.manage.sys.dto.request.PasswordChangeRequest;
import cn.novalon.manage.sys.dto.request.UserRegisterRequest;
import cn.novalon.manage.sys.dto.request.UserUpdateRequest;
import cn.novalon.manage.sys.core.command.CreateUserCommand;
import cn.novalon.manage.sys.core.command.UpdateUserCommand;
import cn.novalon.manage.sys.audit.OperationLog;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Validator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 用户处理器
 * 
 * 文件定义：处理用户相关的HTTP请求，将请求转换为Service层调用
 * 涉及业务：用户查询、创建、更新、删除、密码修改等RESTful API操作
 * 算法：使用WebFlux函数式编程模型处理响应式请求
 * 
 * @author 张翔
 * @date 2026-03-13
 */
@Component
@Tag(name = "用户管理", description = "用户相关操作")
public class SysUserHandler {

    private static final Logger logger = LoggerFactory.getLogger(SysUserHandler.class);
    private final ISysUserService userService;
    private final Validator validator;

    public SysUserHandler(ISysUserService userService, Validator validator) {
        this.userService = userService;
        this.validator = validator;
    }

    @Operation(summary = "获取所有用户", description = "获取系统中所有用户列表")
    public Mono<ServerResponse> getAllUsers(ServerRequest request) {
        boolean includeDeleted = Boolean.valueOf(request.queryParam("includeDeleted").orElse("false"));
        return ServerResponse.ok()
                .body(userService.findAll(includeDeleted), SysUser.class);
    }

    @Operation(summary = "分页获取用户", description = "根据分页参数获取用户列表")
    public Mono<ServerResponse> getUsersByPage(ServerRequest request) {
        int page = Integer.parseInt(request.queryParam("page").orElse("0"));
        int size = Integer.parseInt(request.queryParam("size").orElse("10"));
        String sort = request.queryParam("sort").orElse("id");
        String order = request.queryParam("order").orElse("asc");
        String keyword = request.queryParam("keyword").orElse(null);

        PageRequest pageRequest = new PageRequest();
        pageRequest.setPage(page);
        pageRequest.setSize(size);
        pageRequest.setSort(sort);
        pageRequest.setOrder(order);
        pageRequest.setKeyword(keyword);

        return userService.findUsersByPage(pageRequest)
                .flatMap(response -> ServerResponse.ok().bodyValue(response));
    }

    @Operation(summary = "获取用户总数", description = "获取系统中用户总数")
    public Mono<ServerResponse> getUserCount(ServerRequest request) {
        return userService.count()
                .flatMap(count -> ServerResponse.ok().bodyValue(count));
    }

    @Operation(summary = "根据ID获取用户", description = "根据用户ID获取用户详细信息")
    public Mono<ServerResponse> getUserById(ServerRequest request) {
        Long id = Long.valueOf(request.pathVariable("id"));
        return userService.findById(id)
                .flatMap(user -> {
                    return userService.getUserRoleIds(id)
                            .collectList()
                            .map(roleIds -> {
                                Map<String, Object> userWithRoles = new HashMap<>();
                                userWithRoles.put("id", user.getId());
                                userWithRoles.put("username", user.getUsername());
                                userWithRoles.put("nickname", user.getNickname());
                                userWithRoles.put("email", user.getEmail());
                                userWithRoles.put("phone", user.getPhone());
                                userWithRoles.put("avatar", user.getAvatar());
                                userWithRoles.put("status", user.getStatus());
                                userWithRoles.put("roles", roleIds);
                                userWithRoles.put("createdAt", user.getCreatedAt());
                                userWithRoles.put("updatedAt", user.getUpdatedAt());
                                return userWithRoles;
                            });
                })
                .flatMap(userWithRoles -> ServerResponse.ok().bodyValue(userWithRoles))
                .switchIfEmpty(ServerResponse.notFound().build());
    }

    @Operation(summary = "根据用户名获取用户", description = "根据用户名获取用户详细信息")
    public Mono<ServerResponse> getUserByUsername(ServerRequest request) {
        String username = request.pathVariable("username");
        return userService.findByUsername(username)
                .flatMap(user -> ServerResponse.ok().bodyValue(user))
                .switchIfEmpty(ServerResponse.notFound().build());
    }

    @Operation(summary = "创建用户", description = "创建新用户")
    @OperationLog(operation = "创建用户", module = "用户管理")
    public Mono<ServerResponse> createUser(ServerRequest request) {
        return request.bodyToMono(UserRegisterRequest.class)
                .flatMap(req -> {
                    var violations = validator.validate(req);
                    if (!violations.isEmpty()) {
                        Map<String, String> errors = new HashMap<>();
                        violations.forEach(v -> errors.put(v.getPropertyPath().toString(), v.getMessage()));
                        return ServerResponse.badRequest().bodyValue(errors);
                    }
                    
                    return Mono.just(CreateUserCommand.of(
                            req.getUsername(),
                            req.getPassword(),
                            req.getEmail(),
                            req.getNickname(),
                            req.getPhone(),
                            null,
                            null
                    ))
                    .flatMap(userService::createUser)
                    .flatMap(user -> ServerResponse.status(HttpStatus.CREATED).bodyValue(user));
                });
    }

    @Operation(summary = "更新用户", description = "更新用户信息")
    @OperationLog(operation = "更新用户", module = "用户管理")
    public Mono<ServerResponse> updateUser(ServerRequest request) {
        Long id = Long.valueOf(request.pathVariable("id"));
        return request.bodyToMono(UserUpdateRequest.class)
                .map(req -> {
                    boolean clearRole = Boolean.TRUE.equals(req.getClearRole()) || 
                                       (req.getRoleId() == null && req.getClearRole() != null);
                    return UpdateUserCommand.of(
                            id,
                            null,
                            null,
                            req.getEmail(),
                            req.getRoleId(),
                            req.getStatus(),
                            clearRole
                    );
                })
                .flatMap(userService::updateUser)
                .flatMap(user -> ServerResponse.ok().bodyValue(user))
                .switchIfEmpty(ServerResponse.notFound().build());
    }

    @Operation(summary = "删除用户", description = "物理删除用户")
    @OperationLog(operation = "删除用户", module = "用户管理")
    public Mono<ServerResponse> deleteUser(ServerRequest request) {
        Long id = Long.valueOf(request.pathVariable("id"));
        return userService.findById(id)
                .flatMap(user -> userService.deleteUser(id)
                        .then(ServerResponse.noContent().build()))
                .switchIfEmpty(Mono.error(new RuntimeException("User not found")))
                .onErrorResume(RuntimeException.class, ex -> {
                    if (ex.getMessage().contains("not found")) {
                        return ServerResponse.notFound().build();
                    }
                    return Mono.error(ex);
                });
    }

    @Operation(summary = "修改密码", description = "修改用户密码")
    @OperationLog(operation = "修改密码", module = "用户管理")
    public Mono<ServerResponse> changePassword(ServerRequest request) {
        Long id = Long.valueOf(request.pathVariable("id"));
        return request.bodyToMono(PasswordChangeRequest.class)
                .flatMap(req -> userService.changePassword(id, req.getOldPassword(), req.getNewPassword()))
                .flatMap(user -> ServerResponse.ok().bodyValue(user));
    }

    @Operation(summary = "逻辑删除用户", description = "逻辑删除单个用户")
    public Mono<ServerResponse> logicalDeleteUser(ServerRequest request) {
        Long id = Long.valueOf(request.pathVariable("id"));
        return userService.findById(id)
                .flatMap(user -> userService.logicalDeleteUser(id)
                        .then(ServerResponse.noContent().build()))
                .switchIfEmpty(Mono.error(new RuntimeException("User not found")))
                .onErrorResume(RuntimeException.class, ex -> {
                    if (ex.getMessage().contains("not found")) {
                        return ServerResponse.notFound().build();
                    }
                    return Mono.error(ex);
                });
    }

    @Operation(summary = "批量逻辑删除用户", description = "批量逻辑删除多个用户")
    public Mono<ServerResponse> logicalDeleteUsers(ServerRequest request) {
        return request.bodyToMono(new org.springframework.core.ParameterizedTypeReference<List<Long>>() {
        })
                .flatMap(ids -> userService.logicalDeleteUsers(ids))
                .then(ServerResponse.noContent().build());
    }

    @Operation(summary = "恢复用户", description = "恢复单个被逻辑删除的用户")
    public Mono<ServerResponse> restoreUser(ServerRequest request) {
        Long id = Long.valueOf(request.pathVariable("id"));
        return userService.restoreUser(id)
                .then(ServerResponse.noContent().build())
                .onErrorResume(RuntimeException.class, ex -> {
                    if (ex.getMessage().contains("not found")) {
                        return ServerResponse.notFound().build();
                    }
                    return Mono.error(ex);
                });
    }

    @Operation(summary = "批量恢复用户", description = "批量恢复被逻辑删除的用户")
    public Mono<ServerResponse> restoreUsers(ServerRequest request) {
        return request.bodyToMono(new org.springframework.core.ParameterizedTypeReference<List<Long>>() {
        })
                .flatMap(ids -> userService.restoreUsers(ids))
                .then(ServerResponse.noContent().build());
    }

    @Operation(summary = "检查用户名是否存在", description = "检查指定用户名是否已存在")
    public Mono<ServerResponse> checkUsernameExists(ServerRequest request) {
        String username = request.queryParam("username").orElse(null);
        return userService.existsByUsername(username)
                .flatMap(exists -> ServerResponse.ok().bodyValue(exists));
    }

    @Operation(summary = "检查邮箱是否存在", description = "检查指定邮箱是否已存在")
    public Mono<ServerResponse> checkEmailExists(ServerRequest request) {
        String email = request.queryParam("email").orElse(null);
        return userService.existsByEmail(email)
                .flatMap(exists -> ServerResponse.ok().bodyValue(exists));
    }

    @Operation(summary = "为用户分配角色", description = "为指定用户分配角色列表")
    @OperationLog(operation = "分配角色", module = "用户管理")
    public Mono<ServerResponse> assignRoles(ServerRequest request) {
        Long id = Long.valueOf(request.pathVariable("id"));
        return request.bodyToMono(new org.springframework.core.ParameterizedTypeReference<List<Long>>() {
        })
                .flatMap(roleIds -> userService.assignRolesToUser(id, roleIds))
                .then(ServerResponse.ok().build())
                .onErrorResume(error -> {
                    logger.error("分配角色失败", error);
                    return ServerResponse.status(500).bodyValue("分配角色失败: " + error.getMessage());
                });
    }

    @Operation(summary = "获取用户的角色", description = "根据用户ID获取该用户拥有的所有角色")
    public Mono<ServerResponse> getUserRoles(ServerRequest request) {
        Long id = Long.valueOf(request.pathVariable("id"));
        return ServerResponse.ok()
                .body(userService.getUserRoles(id), cn.novalon.manage.sys.core.domain.SysRole.class);
    }
}
