package org.raddatz.familienarchiv.user;

import java.util.List;
import java.util.Map;
import java.util.UUID;

import jakarta.servlet.http.HttpSession;
import jakarta.validation.Valid;
import org.raddatz.familienarchiv.audit.AuditKind;
import org.raddatz.familienarchiv.audit.AuditService;
import org.raddatz.familienarchiv.auth.AuthService;
import org.raddatz.familienarchiv.user.AdminUpdateUserRequest;
import org.raddatz.familienarchiv.user.ChangePasswordDTO;
import org.raddatz.familienarchiv.user.CreateUserRequest;
import org.raddatz.familienarchiv.user.UpdateProfileDTO;
import org.raddatz.familienarchiv.user.AppUser;
import org.raddatz.familienarchiv.security.Permission;
import org.raddatz.familienarchiv.security.RequirePermission;
import org.raddatz.familienarchiv.user.UserService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import lombok.RequiredArgsConstructor;

@RestController
@RequestMapping("/api/")
@RequiredArgsConstructor
public class UserController {
    private final UserService userService;
    private final AuthService authService;
    private final AuditService auditService;

    @GetMapping("users/me")
    public ResponseEntity<AppUser> getCurrentUser(Authentication authentication) {
        if (authentication == null || !authentication.isAuthenticated()) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
        }
        AppUser user = userService.findByEmail(authentication.getName());
        user.setPassword(null);
        return ResponseEntity.ok(user);
    }

    @PutMapping("users/me")
    public ResponseEntity<AppUser> updateProfile(Authentication authentication,
                                                  @RequestBody UpdateProfileDTO dto) {
        AppUser current = userService.findByEmail(authentication.getName());
        AppUser updated = userService.updateProfile(current.getId(), dto);
        updated.setPassword(null);
        return ResponseEntity.ok(updated);
    }

    @PostMapping("users/me/password")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void changePassword(Authentication authentication,
                               HttpSession session,
                               @RequestBody ChangePasswordDTO dto) {
        AppUser current = userService.findByEmail(authentication.getName());
        userService.changePassword(current.getId(), dto);
        int revoked = authService.revokeOtherSessions(session.getId(), authentication.getName());
        auditService.log(AuditKind.LOGOUT, current.getId(), null, Map.of(
                "reason", "password_change",
                "revokedCount", revoked));
    }

    @GetMapping("users/{id}")
    @RequirePermission(Permission.ADMIN_USER)
    public ResponseEntity<AppUser> getUser(@PathVariable UUID id) {
        AppUser user = userService.getById(id);
        user.setPassword(null);
        return ResponseEntity.ok(user);
    }

    @GetMapping("/users")
    @RequirePermission(Permission.ADMIN_USER)
    public ResponseEntity<List<AppUser>> getAllUsers() {
        List<AppUser> users = userService.getAllUsers();
        return ResponseEntity.ok(users);
    }

    @PostMapping("/users")
    @RequirePermission(Permission.ADMIN_USER)
    public ResponseEntity<AppUser> createUser(Authentication authentication,
                                              @Valid @RequestBody CreateUserRequest request) {
        return ResponseEntity.ok(userService.createUserOrUpdate(actorId(authentication), request));
    }

    @PutMapping("/users/{id}")
    @RequirePermission(Permission.ADMIN_USER)
    public ResponseEntity<AppUser> adminUpdateUser(Authentication authentication,
                                                    @PathVariable UUID id,
                                                    @RequestBody AdminUpdateUserRequest dto) {
        AppUser updated = userService.adminUpdateUser(actorId(authentication), id, dto);
        updated.setPassword(null);
        return ResponseEntity.ok(updated);
    }

    @DeleteMapping("/users/{id}")
    @RequirePermission(Permission.ADMIN_USER)
    public ResponseEntity<Void> deleteUser(Authentication authentication,
                                           @PathVariable UUID id) {
        userService.deleteUser(actorId(authentication), id);
        return ResponseEntity.ok().build();
    }

    @PostMapping("/users/{id}/force-logout")
    @RequirePermission(Permission.ADMIN_USER)
    public ResponseEntity<Map<String, Object>> forceLogout(Authentication authentication,
                                                            @PathVariable UUID id) {
        AppUser target = userService.getById(id);
        int revoked = authService.revokeAllSessions(target.getEmail());
        auditService.log(AuditKind.ADMIN_FORCE_LOGOUT, actorId(authentication), null, Map.of(
                "targetUserId", target.getId().toString(),
                "revokedCount", revoked));
        return ResponseEntity.ok(Map.of("revokedCount", revoked));
    }

    private UUID actorId(Authentication auth) {
        return userService.findByEmail(auth.getName()).getId();
    }

}
