package infrastructure.adapter.input.rest;

import application.helper.ResponseHelper;
import application.usecase.CustomerProductUseCase;
import com.banesco.common.infraestructure.helpers.JsonHelper;
import com.banesco.common.infraestructure.helpers.LoggerHelper;
import domain.dto.request.CustomerRequest;
import domain.dto.response.CustomerResponse;
import domain.dto.response.StatusResponse;
import infrastructure.context.TraceIdContext;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.enums.ParameterIn;
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
import org.eclipse.microprofile.openapi.annotations.media.Content;
import org.eclipse.microprofile.openapi.annotations.media.ExampleObject;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameters;
import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;

@Slf4j
@Path("/customer")
public class CustomerResource {

    // --- DEPENDENCIAS INYECTADAS ---
    private final TraceIdContext traceIdContext;
    private final ResponseHelper responseHelper;

    // -- CASO DE USO
    private final CustomerProductUseCase customerProductUseCase;

    public CustomerResource(
            TraceIdContext traceIdContext,
            ResponseHelper responseHelper,
            CustomerProductUseCase customerProductUseCase
    ) {
        this.traceIdContext = traceIdContext;
        this.responseHelper = responseHelper;
        this.customerProductUseCase = customerProductUseCase;
    }

    @POST
    @Path("/position/evaluate")
    @Operation(
            summary = "Consulta de Productos",
            description = "Orquesta a bus-evaluate-customer-product (BUS Consulta de Producto) para consultar las cuentas del cliente."
    )
    @Parameters({
            @Parameter(
                    name = "requestId",
                    in = ParameterIn.HEADER,
                    description = "Identificador de la solicitud para la trazabilidad.",
                    schema = @Schema(type = SchemaType.STRING),
                    example = "7WCnvznd0CPrBZ0jF4af"
            ),
            @Parameter(
                    name = "appId",
                    required = true,
                    in = ParameterIn.HEADER,
                    description = "Identificador de la aplicación cliente para cargar una configuración de header específica.",
                    schema = @Schema(type = SchemaType.STRING),
                    example = "DANIAPP"
            )
    })
    @RequestBody(
            description = "Cuerpo de la solicitud con los datos necesarios para consultar las cuentas.",
            content = @Content(mediaType = MediaType.APPLICATION_JSON, schema =
            @Schema(implementation = CustomerRequest.class),
                    examples = {
                            @ExampleObject(
                                    name = "Solicitud Estándar de Búsqueda por Producto (TDD)",
                                    summary = "Ejemplo de solicitud de productos (TDD) con éxito",
                                    externalValue = "/openapi-examples/request/customer-product-search-success.json"
                            ),
                            @ExampleObject(
                                name = "Solicitud Estándar de Búsqueda por Producto sin Resultados (TDD)",
                                summary = "Ejemplo de solicitud de productos (TDD) sin resultados",
                                externalValue = "/openapi-examples/request/customer-product-search-wihtout-result.json"
                            ),
                            @ExampleObject(
                                    name = "Solicitud Estándar",
                                    summary = "Ejemplo de solicitud con éxito",
                                    externalValue = "/openapi-examples/request/customer-product-success.json"
                            ),
                            @ExampleObject(
                                    name = "Solicitud Estándar (Sin tokenAssignmentInstance)",
                                    summary = "Ejemplo de solicitud con éxito (sin objeto para OTP)",
                                    externalValue = "/openapi-examples/request/customer-product-success-without-token.json"
                            ),
                            @ExampleObject(
                                    name = "Solicitud con Token",
                                    summary = "Ejemplo de solicitud con token (éxito)",
                                    externalValue = "/openapi-examples/request/customer-product-token-success.json"
                            )
                    }
            )
    )
    @APIResponses(value = {
            @APIResponse(
                    responseCode = "200",
                    description = "Operación Exitosa. Devuelve la lista de productos del cliente.",
                    content = @Content(
                            mediaType = MediaType.APPLICATION_JSON,
                            schema = @Schema(implementation = CustomerResponse.class),
                            examples = {
                                    @ExampleObject(
                                            name = "Búsqueda por Producto",
                                            summary = "Respuesta exitosa",
                                            description = "Realiza busqueda de por tipo de producto (productReferenceSearch).",
                                            externalValue = "/openapi-examples/response/customer-product-search-response.json"
                                    ),
                                    @ExampleObject(
                                        name = "Búsqueda por Producto sin Resultados",
                                        summary = "Respuesta exitosa",
                                        description = "Realiza busqueda de por tipo de producto (productReferenceSearch) sin resultados.",
                                        externalValue = "/openapi-examples/response/customer-product-search-response-without-results.json"
                                    ),
                                    @ExampleObject(
                                            name = "Cuentas Enmascaradas",
                                            summary = "Respuesta exitosa (Enmascaramiento activo)",
                                            description = "La configuración de la app indica que 'encryptionData' es true.",
                                            externalValue = "/openapi-examples/response/customer-product-response.json"
                                    ),
                                    @ExampleObject(
                                            name = "Cuentas Reales",
                                            summary = "Respuesta exitosa (Sin enmascaramiento)",
                                            description = "La configuración de la app indica que 'encryptionData' es false.",
                                            externalValue = "/openapi-examples/response/customer-product-response-unmasked.json"
                                    ),
                                    @ExampleObject(
                                            name = "Sin Resultados",
                                            summary = "Respuesta exitosa (Cliente sin productos)",
                                            description = "La consulta se completó, pero el cliente no tiene productos que coincidan.",
                                            externalValue = "/openapi-examples/response/customer-product-without-results.json"
                                    )
                            }
                    )
            ),
            @APIResponse(
                    responseCode = "401",
                    description = "Error de Autorización o Perfil. El perfil del cliente no es válido o falló una validación de seguridad.",
                    content = @Content(
                            mediaType = MediaType.APPLICATION_JSON,
                            schema = @Schema(implementation = StatusResponse.class),
                            examples = {
                                    @ExampleObject(
                                            name = "Perfil Inválido",
                                            summary = "VRN01 - Perfil no válido",
                                            externalValue = "/openapi-examples/response/invalid-profile.json"
                                    )
                            }
                    )
            ),
            @APIResponse(
                    responseCode = "400",
                    description = "Datos de entrada inválidos, como un token OTP incorrecto o una configuración de app no encontrada.",
                    content = @Content(
                            mediaType = MediaType.APPLICATION_JSON,
                            schema = @Schema(implementation = StatusResponse.class),
                            examples = {
                                    @ExampleObject(
                                            name = "Token Inválido",
                                            summary = "VRN07 - OTP Inválido",
                                            externalValue = "/openapi-examples/response/invalid-token.json"
                                    ),
                                    @ExampleObject(
                                            name = "Configuración no encontrada",
                                            summary = "VRN_CONFIG_NOT_FOUND",
                                            externalValue = "/openapi-examples/response/config-not-found.json"
                                    )
                            }
                    )
            ),
            @APIResponse(
                    responseCode = "404",
                    description = "Recurso no encontrado. Puede ser un usuario BOL, un login vacío.",
                    content = @Content(
                            mediaType = MediaType.APPLICATION_JSON,
                            schema = @Schema(implementation = CustomerResponse.class),
                            examples = {
                                    @ExampleObject(
                                            name = "Usuario no existe",
                                            summary = "AUTH02 - Usuario no existe",
                                            externalValue = "/openapi-examples/response/user-bol-not-exist.json"
                                    ),
                                    @ExampleObject(
                                            name = "Usuario vacío",
                                            summary = "AUTH01 - Login vacío",
                                            externalValue = "/openapi-examples/response/user-not-exist.json"
                                    ),
                            }
                    )
            ),
            @APIResponse(
                    responseCode = "409",
                    description = "CONFLICTO.",
                    content = @Content(
                            mediaType = MediaType.APPLICATION_JSON,
                            schema = @Schema(implementation = StatusResponse.class),
                            examples = {
                                    @ExampleObject(
                                            name = "Conflicto",
                                            summary = "Conflicto (revisar)",
                                            externalValue = "/openapi-examples/response/conflict.json"
                                    )
                            }
                    )
            ),
            @APIResponse(
                    responseCode = "500",
                    description = "Uso Interno. Ocurrio un error inesperado.",
                    content = @Content(
                            mediaType = MediaType.APPLICATION_JSON,
                            schema = @Schema(implementation = StatusResponse.class),
                            examples = {
                                    @ExampleObject(
                                            name = "Uso Interno",
                                            summary = "Uso Interno (revisar)",
                                            externalValue = "/openapi-examples/response/internal-use.json"
                                    )
                            }
                    )
            ),
            @APIResponse(
                    responseCode = "503",
                    description = "Servicio no disponible. Ocurrió un error con una dependencia interna o el servicio está en mantenimiento.",
                    content = @Content(
                            mediaType = MediaType.APPLICATION_JSON,
                            schema = @Schema(implementation = StatusResponse.class),
                            examples = {
                                    @ExampleObject(
                                            name = "Mantenimiento",
                                            summary = "VRN04 - Servicio en mantenimiento",
                                            externalValue = "/openapi-examples/response/service-unavailable.json"
                                    ),
                                    @ExampleObject(
                                            name = "Error de Dependencia",
                                            summary = "Error de CI",
                                            externalValue = "/openapi-examples/response/customer-product-rest-client-error.json"
                                    )
                            }
                    )
            )
    })
    public Response evaluatePosition(
            @HeaderParam("appId") String appId,
            @HeaderParam("customerReferenceFintechId") String customerReferenceFintechId,
            @HeaderParam("customerReferenceUser") String customerReferenceUser,
            @Valid @NotNull(message = "VDE01") CustomerRequest request
    ) {
        final var requestId = traceIdContext.getTraceId();

        log.info(LoggerHelper.buildInfoPrivateRequest(requestId, appId, JsonHelper.getJsonFromObject(request)));

        var result = customerProductUseCase.getCustomerProduct(
                request,
                requestId,
                appId,
                customerReferenceFintechId,
                customerReferenceUser
        );

        if (result.isSuccess()) {
            var customerProducts = result.getSuccessResponse();
            log.info(LoggerHelper.buildInfoPrivateResponse(requestId, "Respuesta del servicio de bus-evaluate-customer-product", customerProducts));

            return Response.ok(customerProducts).build();

        } else {
            var errorCode = result.getErrorCode();
            log.warn(LoggerHelper.buildError(requestId, "Error de negocio manejado en Resource: " + errorCode.statusCode()));

            return responseHelper.buildErrorResponse(errorCode, requestId);
        }
    }
}