package br.gov.sigefp.api.security;

import br.gov.sigefp.admin.domain.UserAccount;
import br.gov.sigefp.admin.domain.UserRole;
import br.gov.sigefp.admin.repository.UserAccountRepository;
import br.gov.sigefp.api.security.dto.JwtResponseDTO;
import br.gov.sigefp.api.security.dto.LoginDTO;
import br.gov.sigefp.api.security.dto.RefreshTokenDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.stream.Collectors;

/**
 * Controller para autenticação JWT.
 */
@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
@Tag(name = "Autenticação", description = "Endpoints para autenticação e gerenciamento de tokens JWT")
public class AuthController {

    private final AuthenticationManager authenticationManager;
    private final JwtTokenProvider tokenProvider;
    private final UserAccountRepository userAccountRepository;
    private final UserDetailsService userDetailsService;

    /**
     * Endpoint de login.
     * POST /api/auth/login
     */
    @Operation(summary = "Autenticar usuário", description = "Autentica um usuário e retorna tokens JWT")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Login realizado com sucesso", content = @Content(schema = @Schema(implementation = JwtResponseDTO.class))),
            @ApiResponse(responseCode = "401", description = "Credenciais inválidas"),
            @ApiResponse(responseCode = "400", description = "Dados de entrada inválidos")
    })
    @PostMapping("/login")
    public ResponseEntity<JwtResponseDTO> login(@Valid @RequestBody LoginDTO loginDTO) {
        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                        loginDTO.getUsername(),
                        loginDTO.getPassword()));

        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        String token = tokenProvider.generateToken(userDetails);
        String refreshToken = tokenProvider.generateRefreshToken(userDetails);

        UserAccount userAccount = userAccountRepository.findByUsername(loginDTO.getUsername())
                .orElseThrow(() -> new RuntimeException("Usuário não encontrado"));

        List<String> roles = userAccount.getUserRoles().stream()
                .map(UserRole::getRole)
                .map(role -> role.getCode())
                .collect(Collectors.toList());

        JwtResponseDTO response = JwtResponseDTO.builder()
                .token(token)
                .refreshToken(refreshToken)
                .type("Bearer")
                .id(userAccount.getId())
                .username(userAccount.getUsername())
                .fullName(userAccount.getFullName())
                .email(userAccount.getEmail())
                .roles(roles)
                .build();

        return ResponseEntity.ok(response);
    }

    /**
     * Endpoint para refresh token.
     * POST /api/auth/refresh
     */
    @Operation(summary = "Renovar token", description = "Gera novos tokens de acesso e refresh usando um refresh token válido")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Tokens renovados com sucesso", content = @Content(schema = @Schema(implementation = JwtResponseDTO.class))),
            @ApiResponse(responseCode = "400", description = "Refresh token inválido ou expirado")
    })
    @PostMapping("/refresh")
    public ResponseEntity<JwtResponseDTO> refreshToken(@Valid @RequestBody RefreshTokenDTO refreshTokenDTO) {
        if (!tokenProvider.validateRefreshToken(refreshTokenDTO.getRefreshToken())) {
            return ResponseEntity.badRequest().build();
        }

        String username = tokenProvider.extractUsername(refreshTokenDTO.getRefreshToken());
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);

        UserAccount userAccount = userAccountRepository.findByUsername(username)
                .orElseThrow(() -> new RuntimeException("Usuário não encontrado"));

        if (!userAccount.getIsActive()) {
            return ResponseEntity.badRequest().build();
        }

        String newToken = tokenProvider.generateToken(userDetails);
        String newRefreshToken = tokenProvider.generateRefreshToken(userDetails);

        List<String> roleCodes = userAccount.getUserRoles().stream()
                .map(UserRole::getRole)
                .map(role -> role.getCode())
                .collect(Collectors.toList());

        JwtResponseDTO response = JwtResponseDTO.builder()
                .token(newToken)
                .refreshToken(newRefreshToken)
                .type("Bearer")
                .id(userAccount.getId())
                .username(userAccount.getUsername())
                .fullName(userAccount.getFullName())
                .email(userAccount.getEmail())
                .roles(roleCodes)
                .build();

        return ResponseEntity.ok(response);
    }

    /**
     * Endpoint de logout (client-side).
     * POST /api/auth/logout
     * Nota: Com JWT stateless, o logout é feito no cliente removendo o token.
     * Este endpoint pode ser usado para logging/auditoria.
     */
    @Operation(summary = "Logout", description = "Endpoint para logout (client-side). Com JWT stateless, o logout é feito removendo o token no cliente")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Logout realizado com sucesso")
    })
    @PostMapping("/logout")
    public ResponseEntity<Void> logout() {
        // Com JWT stateless, o logout é feito no cliente removendo o token
        // Este endpoint pode ser usado para logging/auditoria se necessário
        return ResponseEntity.ok().build();
    }
}
