package com.social.media.interfaces.web.controller;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.social.media.application.user.command.ConfirmPasswordResetCommand;
import com.social.media.application.user.command.CreateUserCommand;
import com.social.media.application.user.command.DeleteUserCommand;
import com.social.media.application.user.command.ResetPasswordCommand;
import com.social.media.application.user.command.RestoreUserCommand;
import com.social.media.application.user.command.UpdateUserCommand;
import com.social.media.application.user.dto.UserResponseDto;
import com.social.media.application.user.handler.ConfirmPasswordResetCommandHandler;
import com.social.media.application.user.handler.CreateUserCommandHandler;
import com.social.media.application.user.handler.DeleteUserCommandHandler;
import com.social.media.application.user.handler.ResetPasswordCommandHandler;
import com.social.media.application.user.handler.RestoreUserCommandHandler;
import com.social.media.application.user.handler.UpdateUserCommandHandler;
import com.social.media.domain.user.aggregate.User;
import com.social.media.domain.user.valueobject.UserId;
import com.social.media.infrastructure.persistence.user.query.UserQueryServiceImpl;
import com.social.media.interfaces.web.dto.user.ConfirmPasswordResetRequest;
import com.social.media.interfaces.web.dto.user.CreateUserRequest;
import com.social.media.interfaces.web.dto.user.ResetPasswordRequest;
import com.social.media.interfaces.web.dto.user.UpdateUserRequest;
import com.social.media.interfaces.web.dto.user.UserResponse;
import com.social.media.interfaces.web.mapper.UserDtoMapper;

import jakarta.validation.Valid;

/**
 * REST Controller for User operations - REFACTORED VERSION
 * All operations now include security validation with userId and companyId
 */
@RestController
@RequestMapping("/api/v1/users")

public class UserController {
    
    private final CreateUserCommandHandler createUserCommandHandler;
    private final UpdateUserCommandHandler updateUserCommandHandler;
    private final DeleteUserCommandHandler deleteUserCommandHandler;
    private final RestoreUserCommandHandler restoreUserCommandHandler;
    private final ResetPasswordCommandHandler resetPasswordCommandHandler;
    private final ConfirmPasswordResetCommandHandler confirmPasswordResetCommandHandler;
    private final UserQueryServiceImpl userQueryService;
    private final UserDtoMapper userDtoMapper;
    
    public UserController(CreateUserCommandHandler createUserCommandHandler,
                         UpdateUserCommandHandler updateUserCommandHandler,
                         DeleteUserCommandHandler deleteUserCommandHandler,
                         RestoreUserCommandHandler restoreUserCommandHandler,
                         ResetPasswordCommandHandler resetPasswordCommandHandler,
                         ConfirmPasswordResetCommandHandler confirmPasswordResetCommandHandler,
                         UserQueryServiceImpl userQueryService,
                         UserDtoMapper userDtoMapper) {
        this.createUserCommandHandler = createUserCommandHandler;
        this.updateUserCommandHandler = updateUserCommandHandler;
        this.deleteUserCommandHandler = deleteUserCommandHandler;
        this.restoreUserCommandHandler = restoreUserCommandHandler;
        this.resetPasswordCommandHandler = resetPasswordCommandHandler;
        this.confirmPasswordResetCommandHandler = confirmPasswordResetCommandHandler;
        this.userQueryService = userQueryService;
        this.userDtoMapper = userDtoMapper;
    }
    
    /**
     * Create a new user
     */
    @PostMapping
    public ResponseEntity<UserResponseDto> createUser(@Valid @RequestBody CreateUserRequest request) {
        var authInfo = getAuthenticatedUserInfo();
        CreateUserCommand command = userDtoMapper.toCreateCommand(request, authInfo.userId());
        UserResponseDto response = createUserCommandHandler.handle(command);
        return ResponseEntity.status(HttpStatus.CREATED).body(response);
    }
    
    /**
     * Get user by ID with security validation
     */
    @GetMapping("/{id}")
    public ResponseEntity<UserResponse> getUserById(@PathVariable Long id) {
        var authInfo = getAuthenticatedUserInfo();
        UserId userId = UserId.of(id);
        User user = userQueryService.findByIdWithSecurity(userId, authInfo.userId().value(), authInfo.companyId())
            .orElseThrow(() -> new RuntimeException("User not found or access denied"));
        UserResponse response = userDtoMapper.toResponse(user);
        return ResponseEntity.ok(response);
    }
    
    /**
     * Get current user's profile
     */
    @GetMapping("/profile")
    public ResponseEntity<UserResponse> getCurrentUserProfile() {
        var authInfo = getAuthenticatedUserInfo();
        User user = userQueryService.findOwnProfile(authInfo.userId(), authInfo.companyId())
            .orElseThrow(() -> new RuntimeException("User profile not found"));
        UserResponse response = userDtoMapper.toResponse(user);
        return ResponseEntity.ok(response);
    }
    
    /**
     * Get all users in company with pagination and security validation
     */
    @GetMapping
    public ResponseEntity<Page<UserResponse>> getAllUsers(Pageable pageable) {
        var authInfo = getAuthenticatedUserInfo();
        Page<User> users = userQueryService.findAllByCompany(authInfo.companyId(), authInfo.userId().value(), pageable);
        Page<UserResponse> response = users.map(userDtoMapper::toResponse);
        return ResponseEntity.ok(response);
    }
    
    /**
     * Get users by status with security validation
     */
    @GetMapping("/status/{status}")
    public ResponseEntity<Page<UserResponse>> getUsersByStatus(
            @PathVariable String status,
            Pageable pageable) {
        var authInfo = getAuthenticatedUserInfo();
        Page<User> users = userQueryService.findByCompanyAndStatus(
                authInfo.companyId(), status, authInfo.userId().value(), pageable);
        Page<UserResponse> response = users.map(userDtoMapper::toResponse);
        return ResponseEntity.ok(response);
    }
    
    /**
     * Get users by type with security validation
     */
    @GetMapping("/type/{userType}")
    public ResponseEntity<Page<UserResponse>> getUsersByType(
            @PathVariable String userType,
            Pageable pageable) {
        var authInfo = getAuthenticatedUserInfo();
        Page<User> users = userQueryService.findByCompanyAndUserType(
                authInfo.companyId(), userType, authInfo.userId().value(), pageable);
        Page<UserResponse> response = users.map(userDtoMapper::toResponse);
        return ResponseEntity.ok(response);
    }
    
    /**
     * Get subordinates (users managed by current user)
     */
    @GetMapping("/subordinates")
    public ResponseEntity<Page<UserResponse>> getSubordinates(Pageable pageable) {
        var authInfo = getAuthenticatedUserInfo();
        Page<User> users = userQueryService.findSubordinates(
                authInfo.companyId(), authInfo.userId().value(), pageable);
        Page<UserResponse> response = users.map(userDtoMapper::toResponse);
        return ResponseEntity.ok(response);
    }
    
    /**
     * Update user
     */
    @PutMapping("/{id}")
    public ResponseEntity<UserResponseDto> updateUser(
            @PathVariable Long id,
            @Valid @RequestBody UpdateUserRequest request) {
        var authInfo = getAuthenticatedUserInfo();
        UserId userId = UserId.of(id);
        UpdateUserCommand command = userDtoMapper.toUpdateCommand(userId, request, authInfo.userId());
        UserResponseDto response = updateUserCommandHandler.handle(command);
        return ResponseEntity.ok(response);
    }
    
    /**
     * Delete user (soft delete)
     */
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        var authInfo = getAuthenticatedUserInfo();
        UserId userId = UserId.of(id);
        DeleteUserCommand command = new DeleteUserCommand(userId, authInfo.userId());
        deleteUserCommandHandler.handle(command);
        return ResponseEntity.noContent().build();
    }
    
    /**
     * Restore a logically deleted user
     */
    @PostMapping("/{id}/restore")
    public ResponseEntity<Void> restoreUser(@PathVariable Long id) {
        var authInfo = getAuthenticatedUserInfo();
        UserId userId = UserId.of(id);
        RestoreUserCommand command = new RestoreUserCommand(userId, authInfo.userId());
        restoreUserCommandHandler.handle(command);
        return ResponseEntity.ok().build();
    }
    
    /**
     * Check if email exists within company
     */
    @GetMapping("/check-email")
    public ResponseEntity<Boolean> checkEmailExists(@RequestParam String email) {
        var authInfo = getAuthenticatedUserInfo();
        boolean exists = userQueryService.existsByEmailAndCompany(email, authInfo.companyId());
        return ResponseEntity.ok(exists);
    }
    
    /**
     * Check if CPF exists within company
     */
    @GetMapping("/check-cpf")
    public ResponseEntity<Boolean> checkCpfExists(@RequestParam String cpf) {
        var authInfo = getAuthenticatedUserInfo();
        boolean exists = userQueryService.existsByCpfAndCompany(cpf, authInfo.companyId());
        return ResponseEntity.ok(exists);
    }
    
    /**
     * Get user count in company
     */
    @GetMapping("/count")
    public ResponseEntity<Long> getUserCount() {
        var authInfo = getAuthenticatedUserInfo();
        long count = userQueryService.countByCompany(authInfo.companyId(), authInfo.userId().value());
        return ResponseEntity.ok(count);
    }
    
    /**
     * Reset password request
     */
    @PostMapping("/reset-password")
    public ResponseEntity<Void> resetPassword(@Valid @RequestBody ResetPasswordRequest request) {
        ResetPasswordCommand command = new ResetPasswordCommand(request.email());
        resetPasswordCommandHandler.handle(command);
        return ResponseEntity.ok().build();
    }
    
    /**
     * Confirm password reset
     */
    @PostMapping("/confirm-password-reset")
    public ResponseEntity<Void> confirmPasswordReset(@Valid @RequestBody ConfirmPasswordResetRequest request) {
        ConfirmPasswordResetCommand command = new ConfirmPasswordResetCommand(request.token(), request.newPassword());
        confirmPasswordResetCommandHandler.handle(command);
        return ResponseEntity.ok().build();
    }
    
    /**
     * Helper method to get authenticated user information
     * This should be properly implemented with your security framework
     */
    private AuthenticatedUserInfo getAuthenticatedUserInfo() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        
        // TODO: Implement proper authentication extraction based on your security setup
        // This is a temporary implementation - replace with actual JWT/session parsing
        
        if (authentication == null || !authentication.isAuthenticated()) {
            throw new RuntimeException("User not authenticated");
        }
        
        // Extract user ID and company ID from authentication
        // This will depend on your security implementation
        Long userId = extractUserIdFromAuthentication(authentication);
        Long companyId = extractCompanyIdFromAuthentication(authentication);
        
        return new AuthenticatedUserInfo(UserId.of(userId), companyId);
    }
    
    private Long extractUserIdFromAuthentication(Authentication authentication) {
        // TODO: Implement based on your JWT/session structure
        // For now, returning a default value - this needs proper implementation
        return 1L; // Temporary
    }
    
    private Long extractCompanyIdFromAuthentication(Authentication authentication) {
        // TODO: Implement based on your JWT/session structure
        // For now, returning a default value - this needs proper implementation
        return 1L; // Temporary
    }
    
    /**
     * Record to hold authenticated user information
     */
    private record AuthenticatedUserInfo(UserId userId, Long companyId) {}
}
