package pl.qumak.xml;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.client.support.interceptor.ClientInterceptor;
import org.springframework.ws.config.annotation.EnableWs;
import org.springframework.ws.server.EndpointInterceptor;
import org.springframework.ws.soap.security.wss4j2.Wss4jSecurityInterceptor;
import org.springframework.ws.soap.security.wss4j2.support.CryptoFactoryBean;
import org.springframework.xml.xsd.SimpleXsdSchema;
import org.springframework.xml.xsd.XsdSchema;
import pl.qumak.Client;
import pl.qumak.GlobalEndpointInterceptor;
import pl.qumak.pull.PullService;
import pl.qumak.push.PushService;

import java.io.IOException;
import java.util.List;

@EnableWs
@Configuration
public class Datex2Config{

    @Value("${keystore.location}")
    private String keyStoreLocation;

    @Value("${keystore.password}")
    private String keyStorePassword;

    @Value("${cert}")
    private String certificate;

    @Value("${cert.pass}")
    private String certificatePassword;

    @Value("${company.name}")
    private String companyName;

    @Bean
    public Wss4jSecurityInterceptor securityInterceptor() throws Exception {
        Wss4jSecurityInterceptor securityInterceptor = new Wss4jSecurityInterceptor();

        securityInterceptor.setSecurementActions("Signature");
        securityInterceptor.setSecurementUsername(certificate);
        securityInterceptor.setSecurementPassword(certificatePassword);
        securityInterceptor.setSecurementSignatureCrypto(getCryptoFactoryBean().getObject());
        securityInterceptor.setValidateRequest(true);
        securityInterceptor.setSkipValidationIfNoHeaderPresent(true);
        securityInterceptor.setValidateResponse(false);
        return securityInterceptor;
    }

    @Bean
    public CryptoFactoryBean getCryptoFactoryBean() throws IOException{
        CryptoFactoryBean cryptoFactoryBean = new CryptoFactoryBean();
        cryptoFactoryBean.setKeyStorePassword(keyStorePassword);
        cryptoFactoryBean.setKeyStoreLocation(new FileSystemResource(keyStoreLocation));
        return cryptoFactoryBean;
    }

    public void addInterceptors(List<EndpointInterceptor> interceptors){
        try {
            interceptors.add(securityInterceptor());
            interceptors.add(payloadValidatingInterceptor());
            interceptors.add(new GlobalEndpointInterceptor());
        } catch (Exception e) {
            throw new RuntimeException("Could not initialize interceptors", e);
        }
    }

    @Bean
    public XsdSchema datex2Schema() {
        return new SimpleXsdSchema(new ClassPathResource("xsd/datex_ii_v3_4/DATEXII_3_MessageContainer.xsd"));
    }

    @Bean
    public Jaxb2Marshaller jaxb2Marshaller() {
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        jaxb2Marshaller.setContextPath("pl.qumak.xsd.datex2v3");
        return jaxb2Marshaller;
    }

    @Bean
    public Client client() throws Exception {
        Client client = new Client();
        client.setMarshaller(jaxb2Marshaller());
        client.setUnmarshaller(jaxb2Marshaller());
        ClientInterceptor[] interceptors = new ClientInterceptor[]{securityInterceptor()};
        client.setInterceptors(interceptors);
        return client;
    }

    @Bean
    public LoggedPayloadValidatingInterceptor payloadValidatingInterceptor() throws IOException {
        LoggedPayloadValidatingInterceptor payloadValidatingInterceptor = new LoggedPayloadValidatingInterceptor();
        payloadValidatingInterceptor.setValidateRequest(true);
        payloadValidatingInterceptor.setValidateResponse(true);
        payloadValidatingInterceptor.setXsdSchema(datex2Schema());
        return payloadValidatingInterceptor;
    }

    @Bean
    public PullService pullService(){
        PullService pullService = new PullService();
        pullService.setCompanyName(companyName);
        return pullService;
    }

    @Bean
    public PushService pushService(){
        PushService pushService = new PushService();
        pushService.setCompanyName(companyName);
        return pushService;
    }
}
