/*
 * Copyright (c) 2019 the Eclipse Milo Authors
 *
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 */

package org.eclipse.milo.opcua.stack.client.config;

import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Optional;

import org.eclipse.milo.opcua.stack.SecurityFixture;
import org.eclipse.milo.opcua.stack.client.UaStackClientConfig;
import org.eclipse.milo.opcua.stack.client.security.ClientCertificateValidator;
import org.eclipse.milo.opcua.stack.core.Stack;
import org.eclipse.milo.opcua.stack.core.channel.EncodingLimits;
import org.eclipse.milo.opcua.stack.core.types.enumerated.UserTokenType;
import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription;
import org.eclipse.milo.opcua.stack.core.types.structured.UserTokenPolicy;
import org.testng.annotations.Test;

import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint;
import static org.testng.Assert.assertEquals;

public class UaStackClientConfigTest extends SecurityFixture {

    private final EndpointDescription endpoint = new EndpointDescription(
        "opc.tcp://localhost:62541",
        null,
        null,
        null,
        null,
        new UserTokenPolicy[]{
            new UserTokenPolicy(
                "anonymous",
                UserTokenType.Anonymous,
                null, null, null)
        },
        null,
        null
    );

    private final ClientCertificateValidator validator = new ClientCertificateValidator() {

        @Override
        public void validateCertificateChain(List<X509Certificate> certificateChain) {}

        @Override
        public void validateCertificateChain(
            List<X509Certificate> certificateChain,
            String applicationUri,
            String... validHostNames
        ) {}

    };

    @Test
    public void testCopy() {
        UaStackClientConfig original = UaStackClientConfig.builder()
            .setEndpoint(endpoint)
            .setKeyPair(clientKeyPair)
            .setCertificate(clientCertificate)
            .setCertificateChain(new X509Certificate[]{clientCertificate})
            .setCertificateValidator(validator)
            .setEncodingLimits(EncodingLimits.DEFAULT)
            .setChannelLifetime(uint(1234))
            .setExecutor(Stack.sharedExecutor())
            .setEventLoop(Stack.sharedEventLoop())
            .setWheelTimer(Stack.sharedWheelTimer())
            .setAcknowledgeTimeout(uint(12345))
            .build();

        UaStackClientConfig copy = UaStackClientConfig.copy(original).build();

        assertEquals(copy.getKeyPair(), original.getKeyPair());
        assertEquals(copy.getCertificate(), original.getCertificate());
        assertEquals(copy.getCertificateChain(), original.getCertificateChain());
        assertEquals(copy.getCertificateValidator(), original.getCertificateValidator());
        assertEquals(copy.getEncodingLimits(), original.getEncodingLimits());
        assertEquals(copy.getChannelLifetime(), original.getChannelLifetime());
        assertEquals(copy.getExecutor(), original.getExecutor());
        assertEquals(copy.getEventLoop(), original.getEventLoop());
        assertEquals(copy.getWheelTimer(), original.getWheelTimer());
        assertEquals(copy.getAcknowledgeTimeout(), original.getAcknowledgeTimeout());
    }

    @Test
    public void testCopyAndModify() {
        UaStackClientConfig original = UaStackClientConfig.builder()
            .setEndpoint(endpoint)
            .setKeyPair(clientKeyPair)
            .setCertificate(clientCertificate)
            .setCertificateValidator(validator)
            .setEncodingLimits(EncodingLimits.DEFAULT)
            .setChannelLifetime(uint(1234))
            .setExecutor(Stack.sharedExecutor())
            .setEventLoop(Stack.sharedEventLoop())
            .setWheelTimer(Stack.sharedWheelTimer())
            .build();

        UaStackClientConfig copy = UaStackClientConfig.copy(
            original,
            builder ->
                builder
                    .setKeyPair(null)
                    .setCertificate(null)
                    .setCertificateChain(null)
                    .setCertificateValidator(null)
                    .setEncodingLimits(null)
                    .setChannelLifetime(uint(0))
                    .setAcknowledgeTimeout(uint(12345))
        );

        assertEquals(copy.getKeyPair(), Optional.empty());
        assertEquals(copy.getCertificate(), Optional.empty());
        assertEquals(copy.getCertificateChain(), Optional.empty());
        assertEquals(copy.getCertificateValidator(), null);
        assertEquals(copy.getEncodingLimits(), null);
        assertEquals(copy.getChannelLifetime(), uint(0));
        assertEquals(copy.getAcknowledgeTimeout(), uint(12345));
    }

}
