using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;

DateTime inserted;

using (var db = new TemporalDbContext())
{
	db.Database.EnsureDeleted();
	db.Database.EnsureCreated();
}
Separate();
using (var db = new TemporalDbContext())
{
	db.AddRange(
		new Employee
		{
			Name = "Jiri Cincura",
			Salary = 10,
		},
		new Employee
		{
			Name = "Peppa Pig",
			Salary = 20,
		});
	db.SaveChanges();
	ListEmployeesHelper(db);
	var jiri = db.Employees.Single(e => e.Name == "Jiri Cincura");
	inserted = db.Entry(jiri).Property<DateTime>("From").CurrentValue;
	db.Remove(jiri);
	db.SaveChanges();
	ListEmployeesHelper(db);

	var historyEmployees = db
		.Employees
		.TemporalAll()
		//.TemporalBetween(DateTime.Now.AddDays(-1), DateTime.Now)
		.OrderBy(x => EF.Property<DateTime>(x, "From"))
		.Select(x => new
			{
				Employee = x,
				From = EF.Property<DateTime>(x, "From"),
				To = EF.Property<DateTime>(x, "To")
			})
		.ToList();
	foreach (var item in historyEmployees)
	{
		WriteLine($"Employee {item.Employee.Name} valid from {item.From} to {item.To}");
	}
}
Separate();
using (var db = new TemporalDbContext())
{
	var jiri = db
		.Employees
		.TemporalAsOf(inserted)
		.Single(e => e.Name == "Jiri Cincura");
	db.Add(jiri);
	db.SaveChanges();
	ListEmployeesHelper(db);
}

static void ListEmployeesHelper(TemporalDbContext db)
{
	var employees = db.Employees.ToList();
	foreach (var employee in employees)
	{
		var employeeEntry = db.Entry(employee);
		var from = employeeEntry.Property<DateTime>("From").CurrentValue;
		var to = employeeEntry.Property<DateTime>("To").CurrentValue;
		WriteLine($"Employee {employee.Name} valid from {from} to {to}.");
	}
}

static void WriteLine(object o)
{
	var oldColor = Console.ForegroundColor;
	Console.ForegroundColor = ConsoleColor.Yellow;
	try
	{
		Console.WriteLine(o);
	}
	finally
	{
		Console.ForegroundColor = oldColor;
	}
}

static void Separate()
{
	Console.ReadLine();
	WriteLine(new string('=', 80));
}

public class TemporalDbContext : DbContext
{
	public DbSet<Employee> Employees => Set<Employee>();

	protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
	{
		base.OnConfiguring(optionsBuilder);
		if (optionsBuilder.IsConfigured)
			return;
		optionsBuilder.UseSqlServer(@"Server=.;Database=netdd;Trusted_Connection=true;ConnectRetryCount=0");
		optionsBuilder.LogTo(Console.WriteLine, new[] { RelationalEventId.CommandExecuting });
		optionsBuilder.EnableSensitiveDataLogging();
	}

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

		modelBuilder.Entity<Employee>()
			.ToTable(
				"Employees",
				x => x.IsTemporal(t =>
				{
					t.HasPeriodStart("From");
					t.HasPeriodEnd("To");
					t.UseHistoryTable("EmployeeHistory");
				}));
	}
}

public class Employee
{
	public Guid Id { get; set; }
	public string Name { get; set; } = null!;
	public decimal Salary { get; set; }
}