using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System;
using WorkFlowCheck.Common.RequestContext;
using WorkFlowCheck.Common.Security;
using WorkFlowCheck.DL.Configurations;
using WorkFlowCheck.DL.Entities;
using WorkFlowCheck.DL.Extensions;
using WorkFlowCheck.DL.Interfaces;

namespace WorkFlowCheck.DL
{
    public class AppDbContext : DbContext
    {
        private readonly IRequestContext _requestContext;
        public AppDbContext(DbContextOptions<AppDbContext> options, IRequestContext requestContext)
                    : base(options)
        {
            _requestContext = requestContext;
        }

        #region Entities DbSet
        public DbSet<Entities.CheckListHeader> CheckListHeaders { get; set; } = null!;
        public DbSet<Entities.CheckListRow> CheckListRows { get; set; } = null!;
        public DbSet<Entities.CheckListTemplateHeader> CheckListTemplateHeaders { get; set; } = null!;
        public DbSet<Entities.CheckListTemplateRow> CheckListTemplateRows { get; set; } = null!;
        public DbSet<Entities.CheckPoint> CheckPoints { get; set; } = null!;
        public DbSet<Entities.Equipment> Equipments { get; set; } = null!;
        public DbSet<Entities.Location> Locations { get; set; } = null!;
        public DbSet<Entities.NumberGeneratorTemplate> NumberGeneratorTemplates { get; set; } = null!;
        public DbSet<Entities.NumberGeneratorTemplateDate> NumberGeneratorTemplateDates { get; set; } = null!;
        public DbSet<Entities.Role> Roles { get; set; } = null!;
        public DbSet<Entities.User> Users { get; set; } = null!;
        public DbSet<Entities.UserRole> UserRoles { get; set; } = null!;
        public DbSet<Entities.RoleCheckListTemplateHeader> RoleCheckListTemplateHeaders { get; set; } = null!;
        public DbSet<Entities.RoleCheckPoint> RoleCheckPoints { get; set; } = null!;
        #endregion



        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.ApplyConfiguration(new CheckListHeaderTypeConfiguration());
            modelBuilder.ApplyConfiguration(new CheckListRowTypeConfiguration());
            modelBuilder.ApplyConfiguration(new CheckListTemplateHeaderTypeConfiguration());
            modelBuilder.ApplyConfiguration(new CheckListTemplateRowTypeConfiguration());
            modelBuilder.ApplyConfiguration(new CheckPointTypeConfiguration());
            modelBuilder.ApplyConfiguration(new EquipmentTypeConfiguration());
            modelBuilder.ApplyConfiguration(new LocationTypeConfiguration());
            modelBuilder.ApplyConfiguration(new NumberGeneratorTypeConfiguration());
            modelBuilder.ApplyConfiguration(new NumberGeneratorDateTypeConfiguration());
            modelBuilder.ApplyConfiguration(new RoleTypeConfiguration());
            modelBuilder.ApplyConfiguration(new RoleCheckListTemplateHeaderTypeConfiguration());
            modelBuilder.ApplyConfiguration(new RoleCheckPointTypeConfiguration());
            modelBuilder.ApplyConfiguration(new UserTypeConfiguration());
            modelBuilder.ApplyConfiguration(new UserRoleTypeConfiguration());


            modelBuilder.RegisterSoftDeleteQueryFilters();

            SeedInit(modelBuilder);
        }
        public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
        {
            SaveChangesCore();
            return await base.SaveChangesAsync(cancellationToken);
        }
        protected virtual void SaveChangesCore()
        {
            var utcNow = DateTime.UtcNow;

            var deletedEntries = ChangeTracker
                  .Entries()
                  .Where(e => e.Entity is ISoftDeletableEntity && e.State == EntityState.Deleted);

            UpdateDeletedEntries(deletedEntries);

            var modifiedEntries = ChangeTracker
                .Entries()
                .Where(e => e.Entity is IAuditableEntity && e.State == EntityState.Modified);

            UpdateModifiedEntires(modifiedEntries, utcNow);

            var addedEntries = ChangeTracker
                   .Entries()
                   .Where(e => e.Entity is IAuditableEntity && e.State == EntityState.Added);

            UpdateAddedEntries(addedEntries, utcNow);
        }
        private void UpdateAddedEntries(IEnumerable<EntityEntry> addedEntries, DateTime utcNow)
        {
            foreach (var entry in addedEntries)
            {
                ((IAuditableEntity)entry.Entity).CreatedAt = utcNow;
                ((IAuditableEntity)entry.Entity).LastModAt = utcNow;
                ((IAuditableEntity)entry.Entity).CreatedBy = _requestContext.CurrentUsername ?? "Admin";
                ((IAuditableEntity)entry.Entity).LastModBy = _requestContext.CurrentUsername ?? "Admin";
            }
        }
        private void UpdateModifiedEntires(IEnumerable<EntityEntry> modifiedEntries, DateTime utcNow)
        {
            foreach (var entry in modifiedEntries)
            {
                ((IAuditableEntity)entry.Entity).LastModAt = utcNow;
                ((IAuditableEntity)entry.Entity).LastModBy = _requestContext.CurrentUsername ?? "Admin";
            }
        }
        private void UpdateDeletedEntries(IEnumerable<EntityEntry> deletedEntries)
        {
            foreach (var entry in deletedEntries)
            {
                ((ISoftDeletableEntity)entry.Entity).IsDeleted = true;
                entry.State = EntityState.Modified;
            }
        }

        private void SeedInit(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<User>().HasData(
                    new User
                    {
                        Id = 1,
                        Email = "admin@nuvolar.hu",
                        FirstName = "Administrator",
                        LastName = "System",
                        IsDeleted = false,
                        UserName = "admin",
                        PasswordHash = PasswordHasher.HashPassword("111111"),
                        CreatedAt = DateTime.UtcNow,
                        CreatedBy = "System",
                        LastModAt = DateTime.UtcNow,
                        LastModBy = "System",
                        JwtToken = "",
                        Active = true,
                        Token2FA = "",
                        NFCActive = true,
                        NFCCode = "00000000"
                    },
                    new User
                    {
                        Id = 2,
                        Email = "user@nuvolar.hu",
                        FirstName = "User",
                        LastName = "System",
                        IsDeleted = false,
                        UserName = "user",
                        PasswordHash = PasswordHasher.HashPassword("222222"),
                        CreatedAt = DateTime.UtcNow,
                        CreatedBy = "System",
                        LastModAt = DateTime.UtcNow,
                        LastModBy = "System",
                        JwtToken = "",
                        Active = true,
                        Token2FA = "",
                        NFCActive = true,
                        NFCCode = "00000000"
                    }
            );
            modelBuilder.Entity<NumberGeneratorTemplate>().HasData(
                new NumberGeneratorTemplate
                {
                    Id = 1,
                    CurrentNumber = 0,
                    DigitFormat = "D4",
                    GenerateType = GenerateType.OnlyYear,
                    LastGeneratedNumber = "",
                    Prefix = "CHK",
                    PrefixSeparator = "-",
                    ShortName = "Ellenőrzési dokumentum sorszámozása",
                    Suffix = "",
                    SuffixSeparator = "-",
                }
             );
            modelBuilder.Entity<NumberGeneratorTemplateDate>().HasData(
                new NumberGeneratorTemplateDate
                {
                    Id = 1,
                    CurrentNumber = 0,
                    LastGeneratedNumber = "",
                    Month = 0,
                    Year = 1,
                    NumberGeneratorTemplateId = 1,
                }
             );
        }
    }
}
