﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using PKISharp.WACS.Clients.IIS;
using PKISharp.WACS.Configuration;
using PKISharp.WACS.DomainObjects;
using PKISharp.WACS.Extensions;
using PKISharp.WACS.Plugins.Interfaces;
using PKISharp.WACS.Plugins.TargetPlugins;
using PKISharp.WACS.Services;
using PKISharp.WACS.UnitTests.Mock.Services;
using System;
using System.Linq;

namespace PKISharp.WACS.UnitTests.Tests.TargetPluginTests
{
    [TestClass]
    public class IISBindingTests
    {
        private readonly ILogService log;
        private readonly IIISClient iis;
        private readonly IISHelper helper;
        private readonly MockPluginService plugins;
        private readonly IUserRoleService userRoleService;

        public IISBindingTests()
        {
            log = new Mock.Services.LogService(false);
            iis = new Mock.Clients.MockIISClient(log);
            helper = new IISHelper(log, iis);
            plugins = new MockPluginService(log);
            userRoleService = new Mock.Services.UserRoleService();
        }

        private IISOptions? Options(string commandLine)
        {
            var optionsParser = new ArgumentsParser(log, plugins, commandLine.Split(' '));
            var arguments = new ArgumentsService(log, optionsParser);
            var x = new IISOptionsFactory(log, helper, arguments, userRoleService);
            return x.Default().Result;
        }

        private Target Target(IISOptions options)
        {
            var plugin = new IIS(log, userRoleService, helper, options);
            return plugin.Generate().Result;
        }

        private void TestHost(string host, long siteId)
        {
            var result = Options($"--siteid {siteId} --host {host}");
            Assert.IsNotNull(result);
            if (result != null)
            {
                Assert.AreEqual(result.IncludeSiteIds.FirstOrDefault(), siteId);
                Assert.AreEqual(result.IncludeHosts.FirstOrDefault(), host);

                var target = Target(result);
                Assert.IsNotNull(target);
                Assert.AreEqual(target.IsValid(log), true);
                Assert.AreEqual(target.CommonName, host);
                Assert.AreEqual(target.Parts.Count(), 1);
                Assert.AreEqual(target.Parts.First().SiteId, siteId);
                Assert.AreEqual(target.Parts.First().Identifiers.Count(), 1);
                Assert.AreEqual(target.Parts.First().Identifiers.First(), host);
            }
           
        }

        [TestMethod]
        public void Regular() => TestHost("test.example.com", 1);

        [TestMethod]
        public void IDNUnicode() => TestHost("经/已經.example.com", 1);

        [TestMethod]
        public void IDNAscii()
        {
            var punyHost = "xn--/-9b3b774gbbb.example.com";
            var uniHost = "经/已經.example.com";
            var siteId = 1;
            var result = Options($"--siteid {siteId} --host {punyHost}");
            Assert.IsNotNull(result);
            if (result != null)
            {
                Assert.AreEqual(result.IncludeSiteIds.FirstOrDefault(), siteId);
                Assert.AreEqual(result.IncludeHosts.FirstOrDefault(), uniHost);

                var target = Target(result);
                Assert.IsNotNull(target);
                Assert.AreEqual(target.IsValid(log), true);
                Assert.AreEqual(target.IIS, true);
                Assert.AreEqual(target.CommonName, uniHost);
                Assert.AreEqual(target.Parts.Count(), 1);
                Assert.AreEqual(target.Parts.First().SiteId, siteId);
                Assert.AreEqual(target.Parts.First().Identifiers.Count(), 1);
                Assert.AreEqual(target.Parts.First().Identifiers.First(), uniHost);
            }
        }

        [TestMethod]
        public void WrongSite()
        {
            var result = Options("--siteid 2 --host test.example.com");
            Assert.IsNull(result);
        }

        [TestMethod]
        public void MissingSite()
        {
            var result = Options("--siteid 999 --host test.example.com");
            Assert.IsNull(result);
        }

        [TestMethod]
        public void IllegalSite()
        {
            var result = Options("--siteid ab --host test.example.com");
            Assert.IsNull(result);
        }

        [TestMethod]
        public void WrongHost()
        {
            var result = Options("--siteid 1 --host doesntexist.example.com");
            Assert.IsNull(result);
        }

        [TestMethod]
        public void BindingMissing()
        {
            var options = new IISBindingOptions() { Host = "doesntexist.example.com", SiteId = 1 };
            var target = Target(options);
            Assert.IsTrue(target is INull);
        }
    }
}
