using JobsMedical.Web.Models;
using Microsoft.EntityFrameworkCore;

namespace JobsMedical.Web.Data;

/// <summary>
/// Seeds reference data (cities, roles, districts) always, and a believable Tehran demo board
/// (facilities/shifts/jobs/raw listings, marked <see cref="Facility.IsDemo"/>) when demo mode is on.
/// Demo seed/clear is idempotent and can be toggled at runtime from the admin panel.
/// </summary>
public static class SeedData
{
    /// <summary>Canonical role taxonomy (name, category, sort). Add new roles here; they're
    /// inserted on every startup if missing, so existing DBs pick them up too.</summary>
    private static readonly (string Name, string Category, int SortOrder)[] CanonicalRoles =
    {
        ("پزشک عمومی", "پزشک", 1),
        ("پزشک متخصص", "پزشک", 2),
        ("پرستار", "پرستار", 3),
        ("ماما", "ماما", 4),
        ("تکنسین اتاق عمل", "تکنسین", 5),
        ("تکنسین فوریت‌های پزشکی", "تکنسین", 6),
        ("کارشناس آزمایشگاه", "تکنسین", 7),
        ("دندانپزشک", "دندانپزشک", 8),
        ("پرستار سالمندان", "پرستار", 9),
    };

    public static async Task EnsureSeededAsync(AppDbContext db, bool includeDemo = true)
    {
        await SeedReferenceAsync(db);
        await EnsureRolesAsync(db);
        if (includeDemo) await SeedDemoAsync(db);
    }

    /// <summary>Idempotently add any canonical role missing from the DB (no-op when all present).</summary>
    public static async Task EnsureRolesAsync(AppDbContext db)
    {
        var existing = await db.Roles.Select(r => r.Name).ToListAsync();
        var added = false;
        foreach (var (name, category, sort) in CanonicalRoles)
            if (!existing.Contains(name))
            {
                db.Roles.Add(new Role { Name = name, Category = category, SortOrder = sort, IsActive = true });
                added = true;
            }
        if (added) await db.SaveChangesAsync();
    }

    // ---------- Reference data (always) ----------
    public static async Task SeedReferenceAsync(AppDbContext db)
    {
        if (await db.Cities.AnyAsync()) return;

        var tehran = new City { Name = "تهران", Province = "تهران", IsActive = true };
        db.Cities.AddRange(tehran,
            new City { Name = "کرج", Province = "البرز", IsActive = false },
            new City { Name = "مشهد", Province = "خراسان رضوی", IsActive = false },
            new City { Name = "اصفهان", Province = "اصفهان", IsActive = false },
            new City { Name = "شیراز", Province = "فارس", IsActive = false });
        await db.SaveChangesAsync();

        // Roles are seeded by EnsureRolesAsync (idempotent, runs every startup).

        foreach (var n in new[] { "سعادت‌آباد", "شهرک غرب", "ولیعصر / پارک‌وی", "نارمک",
                                   "تهرانپارس", "گیشا / برج میلاد", "ونک", "تجریش" })
            db.Districts.Add(new District { Name = n, CityId = tehran.Id });
        await db.SaveChangesAsync();
    }

    // ---------- Demo board (toggleable) ----------
    public static async Task<int> SeedDemoAsync(AppDbContext db)
    {
        if (await db.Facilities.AnyAsync(f => f.IsDemo)) return 0;   // already seeded

        var tehran = await db.Cities.FirstAsync(c => c.Name == "تهران");
        var roles = await db.Roles.OrderBy(r => r.SortOrder).ToListAsync();
        if (roles.Count < 7) return 0;
        var districts = await db.Districts.Where(d => d.CityId == tehran.Id).ToListAsync();
        int Dist(string n) => districts.FirstOrDefault(d => d.Name == n)?.Id ?? districts.First().Id;

        var facilities = new[]
        {
            new Facility { Name = "بیمارستان میلاد", Type = FacilityType.Hospital, CityId = tehran.Id, DistrictId = Dist("گیشا / برج میلاد"), Address = "تهران، بزرگراه همت، روبه‌روی برج میلاد", Phone = "021-82032000", Lat = 35.7448, Lng = 51.3753, IsVerified = true, IsDemo = true },
            new Facility { Name = "بیمارستان دی", Type = FacilityType.Hospital, CityId = tehran.Id, DistrictId = Dist("ولیعصر / پارک‌وی"), Address = "تهران، خیابان ولیعصر، بالاتر از پارک‌وی", Phone = "021-23601", Lat = 35.7986, Lng = 51.4087, IsVerified = true, IsDemo = true },
            new Facility { Name = "کلینیک تخصصی پارسیان", Type = FacilityType.Clinic, CityId = tehran.Id, DistrictId = Dist("سعادت‌آباد"), Address = "تهران، سعادت‌آباد، میدان کاج", Phone = "021-22360000", Lat = 35.7872, Lng = 51.3760, IsVerified = false, IsDemo = true },
            new Facility { Name = "درمانگاه شبانه‌روزی البرز", Type = FacilityType.Polyclinic, CityId = tehran.Id, DistrictId = Dist("نارمک"), Address = "تهران، نارمک، میدان هلال احمر", Phone = "021-77900000", Lat = 35.7448, Lng = 51.5085, IsVerified = true, IsDemo = true },
            new Facility { Name = "بیمارستان آتیه", Type = FacilityType.Hospital, CityId = tehran.Id, DistrictId = Dist("شهرک غرب"), Address = "تهران، شهرک غرب، بلوار فرحزادی", Phone = "021-82721", Lat = 35.7570, Lng = 51.3680, IsVerified = true, IsDemo = true },
            new Facility { Name = "کلینیک درمانی مهر", Type = FacilityType.Clinic, CityId = tehran.Id, DistrictId = Dist("تهرانپارس"), Address = "تهران، تهرانپارس، فلکه دوم", Phone = "021-77700000", Lat = 35.7350, Lng = 51.5400, IsVerified = false, IsDemo = true },
        };
        db.Facilities.AddRange(facilities);
        await db.SaveChangesAsync();

        var today = DateOnly.FromDateTime(DateTime.UtcNow);
        var rng = new Random(20260602);
        var rolePool = new[] { roles[0], roles[0], roles[0], roles[2], roles[2], roles[1], roles[3], roles[4], roles[5], roles[6] };
        var templates = new[]
        {
            (ShiftType.Day,     new TimeOnly(8, 0),  new TimeOnly(14, 0), "شیفت صبح", 1_500_000L),
            (ShiftType.Evening, new TimeOnly(14, 0), new TimeOnly(20, 0), "شیفت عصر", 1_800_000L),
            (ShiftType.Night,   new TimeOnly(20, 0), new TimeOnly(8, 0),  "شیفت شب", 2_500_000L),
            (ShiftType.OnCall,  new TimeOnly(8, 0),  new TimeOnly(8, 0),  "آنکال", 0L),
        };
        var shifts = new List<Shift>();
        foreach (var f in facilities)
            for (var d = 0; d < 14; d++)
            {
                var date = today.AddDays(d);
                for (var i = 0; i < rng.Next(0, 3); i++)
                {
                    var t = templates[rng.Next(templates.Length)];
                    var role = rolePool[rng.Next(rolePool.Length)];
                    var payType = PayType.PerShift; long? amount = t.Item5; int? share = null;
                    if (t.Item1 == ShiftType.OnCall) { payType = PayType.Negotiable; amount = null; }
                    else switch (rng.Next(0, 5))
                    {
                        case 0: payType = PayType.Negotiable; amount = null; break;
                        case 1: payType = PayType.Percentage; amount = null; share = rng.Next(0, 2) == 0 ? 50 : 60; break;
                        case 2: share = rng.Next(0, 2) == 0 ? 40 : 50; break;
                    }
                    shifts.Add(new Shift
                    {
                        FacilityId = f.Id, RoleId = role.Id, Date = date, StartTime = t.Item2, EndTime = t.Item3,
                        ShiftType = t.Item1, SpecialtyRequired = role.Name,
                        Description = $"{t.Item4} - نیازمند {role.Name} مسلط به امور درمانگاه/اورژانس",
                        PayType = payType, PayAmount = amount, SharePercent = share,
                        GenderRequirement = role.Name == "ماما" ? Gender.Female
                            : rng.Next(0, 4) == 0 ? (Gender)rng.Next(1, 3) : Gender.Any,
                        Status = ShiftStatus.Open, Source = ShiftSource.Admin,
                    });
                }
            }
        db.Shifts.AddRange(shifts);

        db.JobOpenings.AddRange(
            new JobOpening { FacilityId = facilities[0].Id, RoleId = roles[2].Id, Title = "استخدام پرستار بخش اورژانس", EmploymentType = EmploymentType.FullTime, SalaryMin = 18_000_000, SalaryMax = 25_000_000, Description = "استخدام تمام‌وقت پرستار جهت بخش اورژانس با سابقه کار.", Requirements = "حداقل ۲ سال سابقه، مسلط به ICU", Status = ShiftStatus.Open },
            new JobOpening { FacilityId = facilities[1].Id, RoleId = roles[0].Id, Title = "پزشک عمومی مقیم", EmploymentType = EmploymentType.Contract, SalaryMin = 40_000_000, SalaryMax = 55_000_000, Description = "پزشک عمومی مقیم جهت بیمارستان، شیفت‌های چرخشی.", Status = ShiftStatus.Open },
            new JobOpening { FacilityId = facilities[2].Id, RoleId = roles[3].Id, Title = "ماما جهت کلینیک زنان", EmploymentType = EmploymentType.PartTime, GenderRequirement = Gender.Female, Description = "همکاری پاره‌وقت ماما در کلینیک تخصصی زنان و زایمان.", Status = ShiftStatus.Open },
            new JobOpening { FacilityId = facilities[4].Id, RoleId = roles[4].Id, Title = "تکنسین اتاق عمل", EmploymentType = EmploymentType.FullTime, SalaryMin = 16_000_000, SalaryMax = 22_000_000, Description = "تکنسین اتاق عمل جهت بیمارستان، تمام‌وقت با بیمه.", Requirements = "مدرک تکنسین اتاق عمل", Status = ShiftStatus.Open },
            new JobOpening { FacilityId = facilities[3].Id, RoleId = roles[0].Id, Title = "پزشک عمومی طرح", EmploymentType = EmploymentType.Plan, SalaryMin = 30_000_000, SalaryMax = 30_000_000, Description = "جذب پزشک عمومی جهت گذراندن طرح در درمانگاه شبانه‌روزی.", Status = ShiftStatus.Open });
        await db.SaveChangesAsync();
        return facilities.Length;
    }

    /// <summary>Remove all demo facilities (cascades their shifts/jobs). Returns rows removed.</summary>
    public static async Task<int> ClearDemoAsync(AppDbContext db)
        => await db.Facilities.Where(f => f.IsDemo).ExecuteDeleteAsync();
}
