using System;
using System.Text;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;

using Microsoft.Extensions.Options;
using Microsoft.Extensions.DependencyInjection;

using Xunit;

using ExtensionMethods;
using ExtensionsTests.Abstractions;
using System.IO;
using System.Threading.Tasks;

namespace ExtensionsTests {
  public class StringExtensions : ServicesBase {

    // private readonly Configuration _configuration;

    // public StringExtensions() {
    //   _configuration = ServiceProvider.GetService<IOptions<Configuration>>()?.Value
    //     ?? throw new NullReferenceException("Configuration not found");
    // }


    [Fact]
    public void Like() => "http://maks-it.com".Like("https:?//maks*.com");

    [Fact]
    public void Left() => string.Equals("https://maks-it.com".Left(4), "http");

    [Fact]
    public void Right() => string.Equals("https://maks-it.com".Right(4), ".com");

    [Fact]
    public void Mid() => string.Equals("https://maks-it.com".Mid(8, 7), "maks-it");

    [Fact]
    public void ToInteger() {
      var value = "0".ToInteger();
      Assert.True(value.GetType() == typeof(int) && value == 0);
    }

    [Fact]
    public void IsInteger() {
      Assert.True("123".IsInteger() && !"abc123".IsInteger());
    }

    [Fact]
    public void Prepend() {
      var sb = new StringBuilder("123").Prepend("abc");
      Assert.Equal("abc123", sb.ToString());
    }

    private enum DummyEnum {
      [Display(Name = "First member")]
      Member1,
      [Display(Name = "Second member")]
      Member2
    }

    [Fact]
    public void ToEnum() {
      Assert.True(DummyEnum.Member1 == "First member".ToEnum<DummyEnum>() && DummyEnum.Member2 == "Member2".ToEnum<DummyEnum>());
    }

    [Fact]
    public void ToNullableEnum() => Assert.True(null == "".ToNullableEnum<DummyEnum>() || DummyEnum.Member1 == "Member1".ToNullableEnum<DummyEnum>());

    [Fact]
    public void ToNull() => Assert.True(null == "".ToNull() && string.Equals("test", "test".ToNull()));

    [Fact]
    public void ToLong() {
      var value = "0".ToLong();
      Assert.True(value.GetType() == typeof(long) && value == 0);
    }

    [Fact]
    public void ToNullableLong() {
      var value = "0".ToNullableLong();
      Assert.True(value == 0 && value.GetType() == typeof(long) && "".ToNullableLong() == null);
    }

    [Fact]
    public void ToInt() {
      var value = "0".ToInt();
      Assert.True(value.GetType() == typeof(int) && value == 0);
    }

    [Fact]
    public void ToNullableInt() {
      var value = "0".ToNullableInt();
      Assert.True(value != null && value.GetType() == typeof(int?) && value == 0 && "".ToNullableInt() == null);
    }

    [Fact]
    public void ToUint() {
      var value = "0".ToUint();
      Assert.True(value.GetType() == typeof(uint) && value == 0);
    }

    [Fact]
    public void ToNullableUint() {
      var value = "0".ToNullableUint();
      Assert.True(value != null && value.GetType() == typeof(uint) && value == 0 && "".ToNullableUint() == null);
    }

    [Fact]
    public void ToDecimal() {
      var value = "0".ToDecimal();
      Assert.True(value.GetType() == typeof(decimal) && value == 0);
    }

    [Fact]
    public void ToNullableDecimal() {
      var value = "0".ToNullableDecimal();
      Assert.True(value != null && value.GetType() == typeof(decimal) && "".ToNullableDecimal() == null);
    }

    [Fact]
    public void ToDouble() {
      var value = "0".ToDouble();
      Assert.True(value.GetType() == typeof(double) && value == 0);
    }

    [Fact]
    public void ToNullableDouble() {
      var value = "0".ToNullableDouble();
      Assert.True(value != null && value.GetType() == typeof(double) && value == 0 && "".ToNullableDouble() == null);
    }

    [Fact]
    public void ToDate() {
      var value = "05/08/1988".ToDate();
      Assert.True(value.GetType() == typeof(DateTime) && value == new DateTime(1988, 08, 05));
    }

    [Fact]
    public void ToNullableDate() {
      var value = "05/08/1988".ToDate();
      Assert.True(value.GetType() == typeof(DateTime) && value == new DateTime(1988, 08, 05) && "".ToNullableDate() == null);
    }

    [Fact]
    public void ToDateTime() {
      var value = "05/08/1988 00:30:00".ToDateTime();
      Assert.True(value.GetType() == typeof(DateTime) && value == new DateTime(1988, 08, 05, 00, 30, 00));
    }

    [Fact]
    public void ToNullableDateTime() {
      var value = "05/08/1988 00:30:00".ToDateTime();
      Assert.True(value.GetType() == typeof(DateTime) && value == new DateTime(1988, 08, 05, 00, 30, 00) && "".ToNullableDateTime() == null);
    }

    [Fact]
    public void ToBool() {
      Assert.True("true".ToBool() && !"false".ToBool());
    }

    [Fact]
    public void ToNullalbeBool() {
      var trueTest = "true".ToNullableBool();
      var falseTest = "false".ToNullableBool();
      if (trueTest == null || falseTest == null)
        Assert.False(true);
      else
        Assert.True(trueTest.Value && !falseTest.Value && "".ToNullableBool() == null);
    }

    [Fact]
    public void ToGuid() {
      var value = "7a11f6ed-d1b6-4d38-9f66-738762c4fde6".ToGuid();
      Assert.True(value.GetType() == typeof(Guid));
    }

    [Fact]
    public void ToNullableGuid() => Assert.Null("".ToNullableGuid());

    [Fact]
    public void StringSplit() => Assert.True(new string[] { "hello", "world" }.SequenceEqual("hello, world".StringSplit(',')));

    [Fact]
    public void ToTitle() => Assert.Equal("Maks-IT", "maks-IT".ToTitle());

    [Fact]
    public void ExtractUrls() => Assert.True(new string[] { "https://maks-it.com/123", "https://git.maks-it.com/123" }
      .SequenceEqual(
        "Here are some urls that we have to extract! This one: https://maks-it.com/123 and this one too https://git.maks-it.com/123"
        .ExtractUrls().Select(x => x.AbsoluteUri.ToString()
        )));

    [Fact]
    public void Format() => Assert.Equal("MAKS-IT is a consulting company", "{0} is a consulting company".Format("MAKS-IT"));

    [Fact]
    public void Excerpt() => Assert.Equal("M...", "MAKS-IT".Excerpt(4));

    private class DummyClass {
      public string? Test { get; set; }
    }

    [Fact]
    public void ToObject() {
      var obj = "{ \"Test\": \"Test\" }".ToObject<DummyClass>();

      if (obj == null)
        Assert.False(true);
      else
        Assert.Equal("Test", obj.Test);
    }

    public static IEnumerable<object[]> GetEmailValidationData() {

      var allData = new List<object[]> {
        new object [] { "BAR.SPORT.SAS.@LEGALMAIL.IT", false },
        new object [] { "DANICONFCOM@PEC..IT", false },
        new object [] { "FRANCESCOF..90@PEC.IT", false },
        new object [] { "grecoornellas.a.s.@pec.it", false },
        new object [] { "lavillamar.@pec.libero.it", false },
        new object [] { "podda.pietro.@tiscali.it", false },
        new object [] { "scads.r.l.@legalmail.it", false },

        new object [] { "ALESSANDRO.DOTTI@ARCHIWORLDPEC.IT", true },
        new object [] { "alessandro.durante@mastertrucksrl.it", true },
        new object [] { "alessandro.elia@pec.lottomatica.it", true },
        new object [] { "ALESSANDRO.EMILIANI@PEC.IT", true },
        new object [] { "alessandro.falco@pec.lottomatica.it", true },
        new object [] { "ALESSANDRO.FANNI@PEC.IT", true },
        new object [] { "ALESSANDRO.FASULO@PEC.IT",	true }
      };

      return allData;
    }

    [Theory]
    [MemberData(nameof(GetEmailValidationData))]
    public void IsValidEmail(string email, bool expected) {
      var result = email.IsValidEmail();
      Assert.Equal(expected, result);
    }

    [Fact]
    public void HTMLToPlainText() {
      var html = @"<Grid>
         <RichTextBox>
             <FlowDocument>
                 <p name=""p1"">Hello</p>
                 <p name=""p2"">World!</p>
              </FlowDocument>
          </RichTextBox>
      </Grid>";

      var result = html.HTMLToPlainText();
      var expected = "Hello \nWorld!";

      Assert.True(string.Compare(expected, result) == 0);
    }


  }
}