#nullable enable

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.Extensions.Logging;

namespace EFCoreDemo
{
	class Program
	{
		static void Main(string[] args)
		{
			using (var db = new MyContext())
			{
				//Console.WriteLine(db.Database.GenerateCreateScript());

				db.Database.EnsureDeleted();
				db.Database.EnsureCreated();

				db.AddRange(GenerateOwners(5));
				db.SaveChanges();
			}
			//using (var db = new MyContext())
			//{
			//	db.Dogs.Where(x => EF.Property<string?>(x, "LastEditedBy") == null).Load();
			//}
			//using (var db = new MyContext())
			//{
			//	db.Dogs.Include(x => x.Detail).Where(x => EF.Property<string?>(x, "LastEditedBy") == null).Load();
			//}
			//using (var db = new MyContext())
			//{
			//	db.Set<OwnerDogCount>()
			//		.FromSqlInterpolated($"select o.FullName_LastName as LastName, coalesce((select count(*) from T_DOGS d where d.OwnerId = o.Id), 0) as DogCount from Owners o")
			//		.OrderBy(x => x.LastName)
			//		.Load();
			//}
		}

		static IList<Owner> GenerateOwners(int count)
		{
			var result = new List<Owner>(count);
			for (var i = 0; i < count; i++)
			{
				result.Add(new Owner()
				{
					Id = Guid.NewGuid(),
					FullName = new FullName($"FirstName_{i}", $"LastName_{i}"),
					Dogs = GenerateDogs(2),
				});
			}
			return result;
		}
		static IList<Dog> GenerateDogs(int count)
		{
			var result = new List<Dog>(count);
			var now = DateTimeOffset.Now;
			for (var i = 0; i < count; i++)
			{
				result.Add(new Dog()
				{
					Name = $"Name_{i}",
					DateOfBirth = now.AddDays(-20),
					DateOfDeath = (count % 2) == 0 ? now : (DateTimeOffset?)null,
					MembershipPaid = (count % 2) == 0,
				});
			}
			return result;
		}
	}

	class MyContext : DbContext
	{
		public DbSet<Dog> Dogs => Set<Dog>();
		public DbSet<Owner> Owners => Set<Owner>();

		protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
		{
			base.OnConfiguring(optionsBuilder);

			optionsBuilder.UseCosmos("https://netdd-ef-demo.documents.azure.com:443/", "YWavNd8VC6BAjA8tyUSnbSKQm98dBG5nbXqCyPX8Vp9twANWgA8975QHp3KmcOdg4vAnY1WXFeidrZkZBGx3yA==", "test");
			optionsBuilder.UseLoggerFactory(MyLoggerFactory);
		}

		static MyLoggerFactory MyLoggerFactory = new MyLoggerFactory();

		protected override void OnModelCreating(ModelBuilder modelBuilder)
		{
			base.OnModelCreating(modelBuilder);

			//modelBuilder.ApplyConfiguration(new DogConfiguration());

			modelBuilder.Entity<Owner>(c =>
			{
				c.OwnsOne(x => x.FullName);
				c.Property(x => x.Points).HasConversion<decimal>(x => x, x => (int)x);
				c.OwnsMany(x => x.Dogs);
				c.ToContainer("Owners");
			});

			//modelBuilder.Entity<DogDetail>(c =>
			//{
			//	//c.ToTable("T_DOGS");
			//});

			//modelBuilder.Entity<OwnerDogCount>(c => c.HasNoKey());

			foreach (var entity in modelBuilder.Model.GetEntityTypes())
			{
				foreach (var property in entity.GetProperties())
				{
					if (property.ClrType == typeof(string))
					{
						property.SetMaxLength(100);
					}
				}
			}
		}
	}

	class Dog
	{
		public int Id { get; set; }
		public string Name { get; set; }
		public DateTimeOffset DateOfBirth { get; set; }
		public DateTimeOffset? DateOfDeath { get; set; }
		public bool MembershipPaid { get; set; }
		public int? OwnerId { get; set; }
		public Owner? Owner { get; set; }
		//public DogDetail Detail { get; set; }

		public Dog()
		{

		}

		Dog(MyContext entityType)
		{

		}
	}

	//class DogDetail
	//{
	//	public int Id { get; }
	//	public int? Foo { get; }
	//	public int? Bar { get; }
	//	public int? Baz { get; }
	//}

	class Owner
	{
		public Guid Id { get; set; }
		public FullName FullName { get; set; }
		public ICollection<Dog> Dogs { get; set; }
		public int Points { get; set; }
	}

	class FullName
	{
		public string FirstName { get; set; }
		public string? MiddleName { get; set; }
		public string LastName { get; set; }

		public FullName(string firstName, string lastName)
		{
			FirstName = firstName;
			LastName = lastName;
		}
		public FullName(string firstName, string middleName, string lastName)
		{
			FirstName = firstName;
			MiddleName = middleName;
			LastName = lastName;
		}
	}

	//class OwnerDogCount
	//{
	//	public string LastName { get; set; }
	//	public int DogCount { get; set; }
	//}

	//class DogConfiguration : IEntityTypeConfiguration<Dog>
	//{
	//	public void Configure(EntityTypeBuilder<Dog> builder)
	//	{
	//		builder.HasKey(x => x.Id);
	//		//builder.ToTable("T_DOGS");
	//		builder.Property(x => x.Id)/*.UseIdentityColumn()*/;
	//		builder.Property(x => x.Name).HasMaxLength(100);

	//		//builder.HasOne(x => x.Owner)
	//		//	.WithMany(x => x!.Dogs)
	//		//	.OnDelete(DeleteBehavior.SetNull)
	//		//	.HasForeignKey(x => x.OwnerId);

	//		builder.Property<string?>("LastEditedBy");

	//		builder.HasQueryFilter(x => x.MembershipPaid);

	//		builder.HasOne(x => x.Detail)
	//			.WithOne()
	//			.HasForeignKey<DogDetail>(x => x.Id);
	//	}
	//}

	class MyLoggerFactory : ILoggerFactory
	{
		public void AddProvider(ILoggerProvider provider)
		{ }

		public ILogger CreateLogger(string categoryName)
		{
			return new MyLogger();
		}

		public void Dispose()
		{ }
	}

	class MyLogger : ILogger, IDisposable
	{
		public IDisposable BeginScope<TState>(TState state) => this;

		public bool IsEnabled(LogLevel logLevel) => true;

		public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
		{
			Console.WriteLine(formatter(state, exception));
		}

		public void Dispose()
		{ }
	}
}
