/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.camel.example.springboot.cxf.otel;

import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.bean.validator.BeanValidationException;
import org.apache.camel.component.cxf.common.message.CxfConstants;
import org.apache.camel.component.minio.MinioConstants;
import org.apache.camel.model.dataformat.JsonLibrary;

import org.springframework.stereotype.Component;

import java.security.SecureRandom;

import io.minio.Result;
import io.minio.messages.Contents;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;

@Component
public class CamelRouter extends RouteBuilder {


    @Override
    public void configure() throws Exception {
        //very raw way, just to handle the validation responses
        onException(BeanValidationException.class)
                .handled(true)
                .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(Response.Status.BAD_REQUEST.getStatusCode()))
                .setBody(simple("${exchangeProperty.CamelExceptionCaught.getMessage()}"));

        // @formatter:off
        from("cxfrs:/api?" +
                    "resourceClasses=org.apache.camel.example.springboot.cxf.otel.RandomService" +
                    "&bindingStyle=SimpleConsumer" +
                    "&providers=jaxrsProvider,openTelemetryProvider" +
                    "&loggingFeatureEnabled=true")
                .to("log:camel-cxf-log?showAll=true")
                .setHeader("methodName", simple("${header.CamelCxfOperationName}"))
                .toD("bean:org.apache.camel.example.springboot.cxf.otel.RandomServiceImpl?method=${header.methodName}");


        from("direct:play").routeId("play")
                .loop(header("attempts"))
                    .process(exchange -> exchange.getIn().getHeaders().clear())
                    .setHeader(CxfConstants.HTTP_METHOD, constant("GET"))
                    .toD("cxfrs:{{service.random.url}}/services/api/generate")
                    .convertBodyTo(RandomNumber.class)
                    .marshal().json(JsonLibrary.Jackson)
                    .process(exchange -> exchange.getIn().getHeaders().clear())
                    .setHeader(CxfConstants.HTTP_METHOD, constant("POST"))
                    .setHeader(CxfConstants.CONTENT_TYPE, constant(MediaType.APPLICATION_JSON))
                    .toD("cxfrs:{{service.even.url}}/services/api/check")
                    .convertBodyTo(RandomNumber.class)
                    .marshal().json(JsonLibrary.Jackson)
                    .process(exchange -> exchange.getIn().getHeaders().clear())
                    .setHeader(CxfConstants.HTTP_METHOD, constant("POST"))
                    .setHeader(CxfConstants.CONTENT_TYPE, constant(MediaType.APPLICATION_JSON))
                    .toD("cxfrs:{{service.odd.url}}/services/api/check")
                .end()
                .setBody(constant(null));

        from("direct:random").routeId("generate-random")
                .loadBalance().random()
                    .to("direct:generate-even")
                    .to("direct:generate-odd")
                .end()
                .convertBodyTo(RandomNumber.class);

        from("direct:generate-even")
                .routeId("generate-even")
                .process(exchange -> {
                    int num = random();
                    while (num % 2 != 0) {
                        num = random();
                    }
                    exchange.getIn().setBody(num);
                });

        from("direct:generate-odd").routeId("generate-odd")
                .process(exchange -> {
                    int num = random();
                    while (num % 2 == 0) {
                        num = random();
                    }
                    exchange.getIn().setBody(num);
                });

        from("direct:save-obj").routeId("save-obj")
                .setHeader(MinioConstants.OBJECT_NAME, header("objectName"))
                .marshal().json(JsonLibrary.Jackson)
                .toD("minio://{{bucket.name}}");

        from("direct:load-results").routeId("load-results")
                .setVariable("results", Results::new)
                .toD("minio://{{bucket.name}}?operation=listObjects")
                .split(body())
                    .process(exchange -> {
						try {
                            exchange.getIn().setHeader(MinioConstants.OBJECT_NAME
                                    , ((Contents) exchange.getIn().getBody(Result.class).get()).objectName());
						} catch (Exception e) {
							throw new RuntimeException(e);
						}
					})
                    .toD("minio://{{bucket.name}}?operation=getObject")
                    .unmarshal().json(JsonLibrary.Jackson, RandomNumber.class)
                    .process(exchange -> exchange.getVariable("results", Results.class)
							.addNumber(exchange.getIn().getBody(RandomNumber.class)))
                .end()
                .setBody(variable("results"));
        // @formatter:on

    }

    private static int random() {
        return new SecureRandom().nextInt(100, 1000);
    }

}
