package dev.lions.user.manager.client.service;

import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.Response;
import org.eclipse.microprofile.rest.client.ext.ResponseExceptionMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;

import jakarta.ws.rs.core.Response.StatusType;

import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

/**
 * Tests unitaires pour RestClientExceptionMapper
 */
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class RestClientExceptionMapperTest {

    private RestClientExceptionMapper exceptionMapper;

    @Mock
    private Response response;

    @Mock
    private StatusType statusType;

    @BeforeEach
    void setUp() {
        exceptionMapper = new RestClientExceptionMapper();
        // Mock getStatusInfo() to return a StatusType
        when(response.getStatusInfo()).thenReturn(statusType);
        when(statusType.getReasonPhrase()).thenReturn("Reason Phrase");
    }

    @Test
    void testHandleBadRequest() {
        when(response.getStatus()).thenReturn(400);
        when(response.readEntity(String.class)).thenReturn("Bad Request");

        RuntimeException exception = exceptionMapper.toThrowable(response);

        assertNotNull(exception);
        assertTrue(exception instanceof RestClientExceptionMapper.BadRequestException);
    }

    @Test
    void testHandleUnauthorized() {
        when(response.getStatus()).thenReturn(401);
        when(response.readEntity(String.class)).thenReturn("Unauthorized");

        RuntimeException exception = exceptionMapper.toThrowable(response);

        assertNotNull(exception);
        assertTrue(exception instanceof RestClientExceptionMapper.UnauthorizedException);
    }

    @Test
    void testHandleForbidden() {
        when(response.getStatus()).thenReturn(403);
        when(response.readEntity(String.class)).thenReturn("Forbidden");

        RuntimeException exception = exceptionMapper.toThrowable(response);

        assertNotNull(exception);
        assertTrue(exception instanceof RestClientExceptionMapper.ForbiddenException);
    }

    @Test
    void testHandleNotFound() {
        when(response.getStatus()).thenReturn(404);
        when(response.readEntity(String.class)).thenReturn("Not Found");

        RuntimeException exception = exceptionMapper.toThrowable(response);

        assertNotNull(exception);
        assertTrue(exception instanceof RestClientExceptionMapper.NotFoundException);
    }

    @Test
    void testHandleInternalServerError() {
        when(response.getStatus()).thenReturn(500);
        when(response.readEntity(String.class)).thenReturn("Internal Server Error");

        RuntimeException exception = exceptionMapper.toThrowable(response);

        assertNotNull(exception);
        assertTrue(exception instanceof RestClientExceptionMapper.InternalServerErrorException);
    }

    @Test
    void testHandleUnknownStatus() {
        when(response.getStatus()).thenReturn(418);
        when(response.readEntity(String.class)).thenReturn("I'm a teapot");

        RuntimeException exception = exceptionMapper.toThrowable(response);

        assertNotNull(exception);
        assertTrue(exception instanceof RestClientExceptionMapper.UnknownHttpStatusException);
    }

    @Test
    void testHandlesMethod() {
        MultivaluedMap<String, Object> headers = new jakarta.ws.rs.core.MultivaluedHashMap<>();
        // La méthode handles vérifie le status code
        assertTrue(exceptionMapper.handles(400, headers));
        assertTrue(exceptionMapper.handles(500, headers));
        assertFalse(exceptionMapper.handles(200, headers));
    }

    @Test
    void testGetPriority() {
        int priority = exceptionMapper.getPriority();
        assertTrue(priority >= 0);
    }
}

