package be.iminds.ilabt.jfed.rspec.ext.user_ssh_keys;

import be.iminds.ilabt.jfed.lowlevel.api.user_spec.UserSpec;
import be.iminds.ilabt.jfed.rspec.model.ModelRspec;
import be.iminds.ilabt.jfed.rspec.model.javafx_impl.FXModelRspec;
import be.iminds.ilabt.jfed.rspec.model.javafx_impl.FXRspecFactory;
import be.iminds.ilabt.jfed.rspec.parser.StaxRspecParser;
import be.iminds.ilabt.jfed.rspec.parser.TestRspecReconstructable;
import be.iminds.ilabt.jfed.rspec.parser.extensions.UserSpecParser;
import be.iminds.ilabt.jfed.rspec.parser.extensions.UserSpecWriter;
import be.iminds.ilabt.jfed.util.JavaFXTest;
import javanet.staxutils.IndentingXMLEventWriter;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.Test;

import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * UserSshKeysRspecTest
 */
public class UserSshKeysRspecTest extends JavaFXTest {
    private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(UserSshKeysRspecTest.class);

    private static final Map<String, String> namespaceInfo() {
        Map<String, String> res = new HashMap<>();
        res.put("jfed-ssh-keys", "http://jfed.iminds.be/rspec/ext/jfed-ssh-keys/1");
        return res;
    }

    private List<UserSpec> createTestSshKeys() {
        List<UserSpec> sshKeys = new ArrayList<>();
        sshKeys.add(new UserSpec("urn:publicid:IDN+example.com+user+tester", "ssh-rsa blabla"));
        List<String> keys = new ArrayList<>();
        keys.add("blibli");
        keys.add("bloblo");
        sshKeys.add(new UserSpec("urn:publicid:IDN+example.com+user+tester2", keys));
        return sshKeys;
    }

    @Test
    public void userSpecToXml() throws Exception {
        List<UserSpec> sshKeys = createTestSshKeys();
        List<String> expectedXml = new ArrayList<>();
        expectedXml.add("<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n" +
                "<jfed-ssh-keys:user-ssh-keys xmlns:jfed-ssh-keys=\"http://jfed.iminds.be/rspec/ext/jfed-ssh-keys/1\" user=\"urn:publicid:IDN+example.com+user+tester\">\n" +
                "  <jfed-ssh-keys:sshkey>ssh-rsa blabla</jfed-ssh-keys:sshkey>\n" +
                "</jfed-ssh-keys:user-ssh-keys>");
        expectedXml.add("<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n" +
                "<jfed-ssh-keys:user-ssh-keys xmlns:jfed-ssh-keys=\"http://jfed.iminds.be/rspec/ext/jfed-ssh-keys/1\" user=\"urn:publicid:IDN+example.com+user+tester2\">\n" +
                "  <jfed-ssh-keys:sshkey>blibli</jfed-ssh-keys:sshkey>\n" +
                "  <jfed-ssh-keys:sshkey>bloblo</jfed-ssh-keys:sshkey>\n" +
                "</jfed-ssh-keys:user-ssh-keys>");

        XMLEventFactory eventFactory = XMLEventFactory.newInstance();

        for (int i = 0; i < sshKeys.size(); i++) {
            UserSpec us = sshKeys.get(i);

            try {
                XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
                outputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);

                StringWriter sw = new StringWriter();

                XMLEventWriter innerEventWriter = outputFactory.createXMLEventWriter(sw);
                XMLEventWriter eventWriter = new IndentingXMLEventWriter(innerEventWriter);

                eventWriter.add(eventFactory.createStartDocument("UTF-8", "1.0", true));

                UserSpecWriter.writeUserSpec(eventFactory, eventWriter, us);

                eventWriter.add(eventFactory.createEndDocument());
                eventWriter.flush();

                String actualXml = sw.getBuffer().toString();

                System.out.println("Created XML:\n" + actualXml);

                Assert.assertEquals(actualXml.trim(), expectedXml.get(i).trim());
            } catch (XMLStreamException e) {
                LOG.error("Error converting to XML: ", e);
                throw new RuntimeException("Error converting to XML: " + e, e);
            }
        }
    }

    @Test
    public void userSpecListInRSpec() throws Throwable {
        ModelRspec rspec = new FXModelRspec("request");
        List<UserSpec> testSshKeys = createTestSshKeys();
        rspec.getSshKeys().addAll(testSshKeys);
        String actualXml = rspec.toGeni3Rspec();
        System.out.println("Created RSpec XML:\n" + actualXml);

        String expectedXml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" +
                "<rspec generated=\"2014-05-30T12:00:21.199+02:00\" generated_by=\"Experimental jFed Rspec Editor\" type=\"request\" xsi:schemaLocation=\"http://www.geni.net/resources/rspec/3 http://www.geni.net/resources/rspec/3/request.xsd\" xmlns=\"http://www.geni.net/resources/rspec/3\" xmlns:jFed=\"http://jfed.iminds.be/rspec/ext/jfed/1\" xmlns:delay=\"http://www.protogeni.net/resources/rspec/ext/delay/1\" xmlns:jfed-ssh-keys=\"http://jfed.iminds.be/rspec/ext/jfed-ssh-keys/1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
                "    <jfed-ssh-keys:user-ssh-keys user=\"urn:publicid:IDN+example.com+user+tester\">\n" +
                "        <jfed-ssh-keys:sshkey>ssh-rsa blabla</jfed-ssh-keys:sshkey>\n" +
                "    </jfed-ssh-keys:user-ssh-keys>\n" +
                "    <jfed-ssh-keys:user-ssh-keys user=\"urn:publicid:IDN+example.com+user+tester2\">\n" +
                "        <jfed-ssh-keys:sshkey>blibli</jfed-ssh-keys:sshkey>\n" +
                "        <jfed-ssh-keys:sshkey>bloblo</jfed-ssh-keys:sshkey>\n" +
                "    </jfed-ssh-keys:user-ssh-keys>\n" +
                "</rspec>";

//        Assert.assertEquals(actualXml, expectedXml);
        TestRspecReconstructable.testSameXml(actualXml, expectedXml);

        TestRspecReconstructable.testXmlStaxReconstructable(actualXml, FXRspecFactory.getInstance());
        TestRspecReconstructable.testRSpecIsReconstructedWithDefaultNamespace(actualXml, FXRspecFactory.getInstance());

        ModelRspec modelRspec = new StaxRspecParser(actualXml, FXRspecFactory.getInstance()).call();
        Assert.assertEquals(modelRspec.getSshKeys().size(), 2);
        Assert.assertEquals(modelRspec.getSshKeys(), testSshKeys);
    }


    private List<UserSpec> unmarshalUserSpecList(String xml) throws Exception {
        return new UserSpecParser(xml).call();

    }

    private String marshalUserSpecList(List<UserSpec> userSpecList) throws Exception {
        return new UserSpecWriter(userSpecList).call();
    }
}
