/*
 * 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.component.as2;

import java.io.IOException;
import java.time.Duration;
import java.util.concurrent.TimeUnit;

import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.as2.api.AS2ClientConnection;
import org.apache.camel.component.as2.api.AS2ClientManager;
import org.apache.camel.component.as2.api.AS2MediaType;
import org.apache.camel.component.as2.api.AS2MessageStructure;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.http.common.HttpMessage;
import org.apache.camel.test.AvailablePortFinder;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

/**
 * Test that the server adds a Bearer Auth authorization header when sending an async MDN.
 */
public class AS2ServerBearerAuthHeaderTest extends AbstractAS2ITSupport {

    private static final String MDN_ACCESS_TOKEN = "MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3";
    @RegisterExtension
    AvailablePortFinder.Port targetPort = AvailablePortFinder.find();
    @RegisterExtension
    AvailablePortFinder.Port jettyPort = AvailablePortFinder.find();
    private static final String EDI_MESSAGE = """
            UNB+UNOA:1+005435656:1+006415160:1+060515:1434+00000000000778'
            UNH+00000000000117+INVOIC:D:97B:UN'
            BGM+380+342459+9'
            DTM+3:20060515:102'
            RFF+ON:521052'
            NAD+BY+792820524::16++CUMMINS MID-RANGE ENGINE PLANT'
            NAD+SE+005435656::16++GENERAL WIDGET COMPANY'
            CUX+1:USD'
            LIN+1++157870:IN'
            IMD+F++:::WIDGET'
            QTY+47:1020:EA'
            ALI+US'
            MOA+203:1202.58'
            PRI+INV:1.179'
            LIN+2++157871:IN'
            IMD+F++:::DIFFERENT WIDGET'
            QTY+47:20:EA'
            ALI+JP'
            MOA+203:410'
            PRI+INV:20.5'
            UNS+S'
            MOA+39:2137.58'
            ALC+C+ABG'
            MOA+8:525'
            UNT+23+00000000000117'
            UNZ+1+00000000000778'
            """;

    // verify that the jetty server receives a Bearer Auth header
    @Test
    public void serverRouteWithBearerAuthConfig() throws Exception {
        clientSend("/bearer", "http://localhost:" + jettyPort.getPort() + "/receiptsWithBearerAuth");

        MockEndpoint mockEndpoint = getMockEndpoint("mock:as2RcvRcptMsgs2");
        mockEndpoint.expectedMinimumMessageCount(1);
        mockEndpoint.setResultWaitTime(TimeUnit.MILLISECONDS.convert(5, TimeUnit.SECONDS));
        mockEndpoint.assertIsSatisfied();
    }

    @Override
    protected RouteBuilder createRouteBuilder() {
        return new RouteBuilder() {
            public void configure() {

                Processor tokenHeaderProc = exchange -> {
                    HttpMessage message = exchange.getIn(HttpMessage.class);
                    assertNotNull(message.getHeader("Authorization"));
                    assertEquals("Bearer " + MDN_ACCESS_TOKEN, message.getHeader("Authorization"));
                };

                from(String.format("as2://server/listen?requestUriPattern=/bearer&mdnAccessToken=%s",
                        MDN_ACCESS_TOKEN))
                        .to("mock:as2RcvMsgs");

                from("jetty:http://localhost:" + jettyPort.getPort() + "/receiptsWithBearerAuth")
                        .process(tokenHeaderProc)
                        .to("mock:as2RcvRcptMsgs2");
            }
        };
    }

    private void clientSend(String requestUri, String receiptDeliveryOption) throws Exception {
        AS2ClientConnection clientConnection = getAs2ClientConnection();
        new AS2ClientManager(clientConnection).send(EDI_MESSAGE, requestUri, "Test Case", "mrAS@example.org", "878051556",
                "878051556", AS2MessageStructure.PLAIN,
                AS2MediaType.APPLICATION_EDIFACT, null, null, null, null, null,
                null, "mrAS@example.org", "sha1,md5", null, null, null, receiptDeliveryOption,
                null, null, null);
    }

    private AS2ClientConnection getAs2ClientConnection() throws IOException {
        return new AS2ClientConnection(
                "1.1", "Camel AS2 Endpoint", "example.org", "localhost", targetPort.getPort(), Duration.ofSeconds(5),
                Duration.ofSeconds(5), 5, Duration.ofMinutes(15), null, null);
    }

    @Override
    protected void customizeConfiguration(AS2Configuration configuration) {
        configuration.setServerPortNumber(targetPort.getPort());
    }
}
