using Indotalent.ConfigBackEnd.Interfaces;
using Indotalent.Data.Entities;
using Indotalent.Infrastructure.Authentication.Identity;
using Indotalent.Infrastructure.Authorization.Identity;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

namespace Indotalent.Infrastructure.Database;

public static class DatabaseSeeder
{
    private static string? adminUserId;
    private static string? tenantId;
    public static async Task SeedAsync(IServiceProvider serviceProvider)
    {
        var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
        var userManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
        var configuration = serviceProvider.GetRequiredService<IConfiguration>();
        var context = serviceProvider.GetRequiredService<AppDbContext>();

        var currentUserService = serviceProvider.GetRequiredService<ICurrentUserService>();

        await SeedIdentityAsync(roleManager, userManager, configuration);
        currentUserService.UserId = adminUserId;

        await SeedDemoTenantAsync(context);
        currentUserService.TenantId = tenantId;

        await SeedCurrenciesAsync(context);
        await SeedCompanyAsync(context);
        await SeedTaxAsync(context);
        await SeedSystemWarehouseAsync(context);

        await DatabaseSeederDemo.SeedAsync(serviceProvider);
    }

    private static async Task SeedDemoTenantAsync(AppDbContext context)
    {
        var existingTenant = await context.Set<Tenant>().FirstOrDefaultAsync(t => t.Name == "Demo Tenant");

        if (existingTenant == null)
        {
            var newTenant = new Tenant
            {
                Name = "Demo Tenant",
                Description = "Initial system tenant for demonstration and seed data.",
                Street = "Sudirman Street No. 123",
                City = "Bandung",
                State = "West Java",
                ZipCode = "40111",
                Country = "Indonesia",
                PhoneNumber = "+62221234567",
                EmailAddress = "hi@indotalent.com",
                Website = "https://indotalent.com",
                IsActive = true
            };

            await context.Set<Tenant>().AddAsync(newTenant);
            await context.SaveChangesAsync();

            tenantId = newTenant.Id;
        }
        else
        {
            tenantId = existingTenant.Id;
        }

        if (!string.IsNullOrEmpty(adminUserId) && !string.IsNullOrEmpty(tenantId))
        {
            var isMapped = await context.Set<TenantUser>()
                .AnyAsync(tu => tu.TenantId == tenantId && tu.UserId == adminUserId);

            if (!isMapped)
            {
                var tenantUser = new TenantUser
                {
                    TenantId = tenantId,
                    UserId = adminUserId,
                    Summary = "Administrator default member mapping",
                    IsActive = true
                };

                await context.Set<TenantUser>().AddAsync(tenantUser);
                await context.SaveChangesAsync();
            }
        }
    }

    private static async Task SeedIdentityAsync(RoleManager<IdentityRole> roleManager, UserManager<ApplicationUser> userManager, IConfiguration configuration)
    {
        var adminSettings = configuration.GetSection("IdentitySettings:DefaultAdmin").Get<DefaultAdminSettings>();
        if (adminSettings == null) return;

        foreach (var roleName in ApplicationRoles.AllRoles)
        {
            if (!await roleManager.RoleExistsAsync(roleName))
            {
                await roleManager.CreateAsync(new IdentityRole(roleName));
            }
        }

        var existingUser = await userManager.FindByEmailAsync(adminSettings.Email);
        if (existingUser == null)
        {
            var defaultAdmin = DefaultUserConfig.GetAdminUser(adminSettings);
            var createAdmin = await userManager.CreateAsync(defaultAdmin, adminSettings.Password);

            if (createAdmin.Succeeded)
            {
                await userManager.AddToRolesAsync(defaultAdmin, ApplicationRoles.AllRoles);
                adminUserId = defaultAdmin.Id;
            }
        }
    }

    private static async Task SeedCurrenciesAsync(AppDbContext context)
    {
        if (await context.Set<Currency>().AnyAsync()) return;

        var currencies = new List<Currency>
        {
            new() { Name = "US Dollar", Code = "USD", Symbol = "$", Description = "United States official currency", CountryOwner = "United States" },
            new() { Name = "Euro", Code = "EUR", Symbol = "€", Description = "Eurozone member states currency", CountryOwner = "European Union" },
            new() { Name = "British Pound", Code = "GBP", Symbol = "£", Description = "Official currency of the UK", CountryOwner = "United Kingdom" },
            new() { Name = "Indonesian Rupiah", Code = "IDR", Symbol = "Rp", Description = "Official currency of Indonesia", CountryOwner = "Indonesia" }
        };

        await context.Set<Currency>().AddRangeAsync(currencies);
        await context.SaveChangesAsync();
    }

    private static async Task SeedCompanyAsync(AppDbContext context)
    {
        if (await context.Set<Company>().AnyAsync()) return;

        var usdCurrency = await context.Set<Currency>().FirstOrDefaultAsync(x => x.Code == "USD");
        if (usdCurrency == null) return;

        var companies = new List<Company>
        {
            new()
            {
                Name = "Acme Global Solutions Inc.",
                Description = "A leading provider of enterprise-grade cloud software solutions.",
                IsDefault = true,
                CurrencyId = usdCurrency.Id,
                TaxIdentification = "EIN 12-3456789",
                BusinessLicense = "LC-987654321",
                StreetAddress = "One World Trade Center, Suite 85",
                City = "New York",
                StateProvince = "NY",
                ZipCode = "10007",
                Phone = "+1 212 555 0198",
                Email = "hr@acmeglobal.com",
                SocialMediaLinkedIn = "linkedin.com/company/acme-global",
                CompanyLogo = "/images/logos/acme-logo.png",
                OtherInformation1 = "Corporate Headquarters",
                OtherInformation2 = "Technology & SaaS",
                OtherInformation3 = "Fortune 500 Candidate"
            }
        };

        await context.Set<Company>().AddRangeAsync(companies);
        await context.SaveChangesAsync();
    }

    private static async Task SeedTaxAsync(AppDbContext context)
    {
        if (await context.Set<Tax>().AnyAsync()) return;

        var taxes = new List<Tax>
        {
            new Tax { Code = "NOTAX", Name = "NOTAX", PercentageValue = 0 },
            new Tax { Code = "T10", Name = "T10", PercentageValue = 10 },
            new Tax { Code = "T15", Name = "T15", PercentageValue = 15 },
            new Tax { Code = "T20", Name = "T20", PercentageValue = 20 },
        };

        await context.Set<Tax>().AddRangeAsync(taxes);
        await context.SaveChangesAsync();
    }

    private static async Task SeedSystemWarehouseAsync(AppDbContext context)
    {
        if (await context.Set<Warehouse>().AnyAsync(x => x.SystemWarehouse == true)) return;

        var warehouses = new List<Warehouse>
        {
            new Warehouse { Name = "Customer", SystemWarehouse = true },
            new Warehouse { Name = "Vendor", SystemWarehouse = true },
            new Warehouse { Name = "Transfer", SystemWarehouse = true },
            new Warehouse { Name = "Adjustment", SystemWarehouse = true },
            new Warehouse { Name = "StockCount", SystemWarehouse = true },
            new Warehouse { Name = "Scrapping", SystemWarehouse = true }
        };

        await context.Set<Warehouse>().AddRangeAsync(warehouses);
        await context.SaveChangesAsync();
    }

}