using Indotalent.ConfigBackEnd.Extensions;
using Indotalent.Data.Entities;
using Indotalent.Data.Enums;
using Microsoft.EntityFrameworkCore;

namespace Indotalent.Infrastructure.Database.Demo;

public static class BookingSeeder
{
    public static async Task GenerateDataAsync(AppDbContext context)
    {
        if (await context.Booking.AnyAsync()) return;

        var random = new Random();
        var bookingStatusValues = Enum.GetValues(typeof(BookingStatus)).Cast<BookingStatus>().ToList();
        var entityName = nameof(Booking);

        var dateEnd = DateTime.Now.AddMonths(6);
        var dateStart = dateEnd.AddMonths(-6);

        var bookingResources = await context.BookingResource
            .Select(x => x.Id)
            .ToListAsync();

        if (!bookingResources.Any()) return;

        var dummyLocations = new List<string>
        {
            "123 Main St, New York",
            "456 Elm St, Los Angeles",
            "789 Pine St, Chicago",
            "101 Maple St, Houston",
            "202 Oak St, Phoenix",
            "303 Birch St, Philadelphia",
            "404 Cedar St, San Antonio",
            "505 Walnut St, San Diego",
            "606 Aspen St, Dallas",
            "707 Spruce St, San Jose"
        };

        for (DateTime date = dateStart; date < dateEnd; date = date.AddMonths(1))
        {
            DateTime[] transactionDates = GenerateRandomDays(date.Year, date.Month, 12);
            foreach (DateTime transDate in transactionDates)
            {
                TimeSpan randomTime = TimeSpan.FromHours(random.Next(8, 12));
                DateTime startTime = transDate.Date.Add(randomTime);

                var autoNo = await context.GenerateAutoNumberAsync(
                    entityName: entityName,
                    prefixTemplate: $"{entityName.ToShortNameConsonant(3)}/{{Year}}/"
                );

                var booking = new Booking
                {
                    Subject = autoNo,
                    AutoNumber = autoNo,
                    StartTime = startTime,
                    EndTime = startTime.AddHours(random.Next(2, 12)),
                    BookingResourceId = GetRandomValue(bookingResources, random),
                    Status = bookingStatusValues[random.Next(bookingStatusValues.Count)],
                    Location = GetRandomValue(dummyLocations, random)
                };

                await context.Booking.AddAsync(booking);
            }
        }

        await context.SaveChangesAsync();
    }

    private static DateTime[] GenerateRandomDays(int year, int month, int count)
    {
        var random = new Random();
        int daysInMonthCount = DateTime.DaysInMonth(year, month);
        return Enumerable.Range(1, count)
            .Select(_ => new DateTime(year, month, random.Next(1, daysInMonthCount + 1)))
            .ToArray();
    }

    private static T GetRandomValue<T>(List<T> list, Random random)
    {
        return list[random.Next(list.Count)];
    }
}