using Hangfire;
using Hangfire.States;
using Hangfire.Dashboard;
using Hangfire.PostgreSql;
using Hangfire.MemoryStorage;
using System.Linq.Expressions;
using QuantEngine.Application.Services;
using QuantEngine.Infrastructure.Data;

namespace QuantEngine.Web.Services;

/// <summary>
/// Scheduler Service for managing background jobs with Hangfire
/// </summary>
public class SchedulerService
{
    private readonly ILogger<SchedulerService> _logger;
    private readonly IBackgroundJobClient _jobClient;
    private readonly IRecurringJobManager _recurringJobManager;

    public SchedulerService(
        ILogger<SchedulerService> logger,
        IBackgroundJobClient jobClient,
        IRecurringJobManager recurringJobManager)
    {
        _logger = logger;
        _jobClient = jobClient;
        _recurringJobManager = recurringJobManager;
    }

    /// <summary>
    /// Initialize scheduled jobs
    /// </summary>
    public void InitializeSchedules()
    {
        try
        {
            _logger.LogInformation("Initializing Hangfire schedules...");

            // Daily data collection at 9:00 AM
            _recurringJobManager.AddOrUpdate(
                "daily-collection",
                () => RunDailyCollectionAsync(),
                "0 9 * * *",  // Every day at 9:00 AM
                new RecurringJobOptions { TimeZone = TimeZoneInfo.Local }
            );

            // Hourly price update (during market hours 9 AM - 4 PM)
            _recurringJobManager.AddOrUpdate(
                "hourly-price-update",
                () => UpdatePricesAsync(),
                "0 9-15 * * 1-5",  // Every hour, 9 AM to 3 PM, Mon-Fri
                new RecurringJobOptions { TimeZone = TimeZoneInfo.Local }
            );

            // Weekly report generation (Friday at 5:00 PM)
            _recurringJobManager.AddOrUpdate(
                "weekly-report",
                () => GenerateWeeklyReportAsync(),
                "0 17 * * 5",  // Every Friday at 5:00 PM
                new RecurringJobOptions { TimeZone = TimeZoneInfo.Local }
            );

            // Monthly optimization (First day of month at 2:00 AM)
            _recurringJobManager.AddOrUpdate(
                "monthly-optimization",
                () => RunMonthlyOptimizationAsync(),
                "0 2 1 * *",  // First day of month at 2:00 AM
                new RecurringJobOptions { TimeZone = TimeZoneInfo.Local }
            );

            _logger.LogInformation("Hangfire schedules initialized successfully");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error initializing Hangfire schedules");
        }
    }

    /// <summary>
    /// Run daily data collection
    /// </summary>
    public async Task RunDailyCollectionAsync()
    {
        try
        {
            _logger.LogInformation("Starting daily data collection job at {Time}", DateTime.Now);

            // List of tickers to collect
            var tickers = new[] { "005930", "000660", "051910", "005380", "010140", "005490" };

            foreach (var ticker in tickers)
            {
                // Simulate data collection
                await Task.Delay(100);
                _logger.LogInformation("Collected data for ticker: {Ticker}", ticker);
            }

            _logger.LogInformation("Daily data collection completed at {Time}", DateTime.Now);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error during daily collection");
        }
    }

    /// <summary>
    /// Update prices hourly
    /// </summary>
    public async Task UpdatePricesAsync()
    {
        try
        {
            _logger.LogInformation("Starting hourly price update at {Time}", DateTime.Now);

            var tickers = new[] { "005930", "000660", "051910" };

            foreach (var ticker in tickers)
            {
                try
                {
                    // Enqueue price update as background job
                    _jobClient.Enqueue(() => FetchPriceAsync(ticker));
                }
                catch (Exception ex)
                {
                    _logger.LogWarning(ex, "Failed to enqueue price update for {Ticker}", ticker);
                }
            }

            _logger.LogInformation("Hourly price update completed");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error during price update");
        }
    }

    /// <summary>
    /// Fetch price for specific ticker
    /// </summary>
    public async Task FetchPriceAsync(string ticker)
    {
        try
        {
            _logger.LogInformation("Fetching price for ticker: {Ticker}", ticker);
            // TODO: Implement actual price fetching
            await Task.Delay(50);
            _logger.LogInformation("Price fetched successfully for {Ticker}", ticker);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error fetching price for {Ticker}", ticker);
        }
    }

    /// <summary>
    /// Generate weekly report
    /// </summary>
    public async Task GenerateWeeklyReportAsync()
    {
        try
        {
            _logger.LogInformation("Starting weekly report generation at {Time}", DateTime.Now);

            // TODO: Implement report generation logic
            await Task.Delay(500);

            _logger.LogInformation("Weekly report generated successfully");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error generating weekly report");
        }
    }

    /// <summary>
    /// Run monthly optimization
    /// </summary>
    public async Task RunMonthlyOptimizationAsync()
    {
        try
        {
            _logger.LogInformation("Starting monthly optimization at {Time}", DateTime.Now);

            // TODO: Implement optimization logic
            await Task.Delay(1000);

            _logger.LogInformation("Monthly optimization completed");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error during monthly optimization");
        }
    }

    /// <summary>
    /// Enqueue one-time job
    /// </summary>
    public string EnqueueJob(string jobName, Expression<Func<Task>> job)
    {
        var jobId = _jobClient.Enqueue(job);
        _logger.LogInformation("Enqueued job {JobName} with ID {JobId}", jobName, jobId);
        return jobId;
    }

    /// <summary>
    /// Get job status
    /// </summary>
    public string? GetJobStatus(string jobId)
    {
        return JobStorage.Current.GetConnection().GetJobData(jobId)?.State;
    }

    /// <summary>
    /// Cancel scheduled job
    /// </summary>
    public void CancelScheduledJob(string jobName)
    {
        _recurringJobManager.RemoveIfExists(jobName);
        _logger.LogInformation("Cancelled scheduled job: {JobName}", jobName);
    }
}

/// <summary>
/// Extension methods for Hangfire registration
/// </summary>
public static class HangfireServiceExtensions
{
    /// <summary>
    /// Register Hangfire with SQL Server storage
    /// </summary>
    public static IServiceCollection AddHangfireServices(
        this IServiceCollection services,
        string connectionString)
    {
        // Add Hangfire services
        services.AddHangfire(configuration =>
        {
            configuration
                .SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
                .UseSimpleAssemblyNameTypeSerializer()
                .UseRecommendedSerializerSettings();

            try
            {
                using (var conn = new Npgsql.NpgsqlConnection(connectionString))
                {
                    conn.Open();
                }

                configuration.UsePostgreSqlStorage(options => options.UseNpgsqlConnection(connectionString), new PostgreSqlStorageOptions
                {
                    QueuePollInterval = TimeSpan.FromSeconds(15),
                    PrepareSchemaIfNecessary = true
                });
                Console.WriteLine("[Hangfire] Configured PostgreSQL storage successfully.");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[Hangfire] PostgreSQL connection failed ({ex.Message}). Falling back to MemoryStorage.");
                configuration.UseMemoryStorage();
            }
        });

        // Add Hangfire server
        services.AddHangfireServer(options =>
        {
            options.WorkerCount = Environment.ProcessorCount * 2;
            options.Queues = new[] { "default" };
        });

        // Register scheduler service
        services.AddScoped<SchedulerService>();

        return services;
    }

    /// <summary>
    /// Use Hangfire dashboard and initialize schedules
    /// </summary>
    public static IApplicationBuilder UseHangfireSetup(
        this IApplicationBuilder app,
        IServiceProvider serviceProvider)
    {
        // Use Hangfire Dashboard
        app.UseHangfireDashboard("/hangfire", new DashboardOptions
        {
            Authorization = new[] { new HangfireAuthorizationFilter() }
        });

        // Initialize schedules
        var schedulerService = serviceProvider.GetRequiredService<SchedulerService>();
        schedulerService.InitializeSchedules();

        return app;
    }
}

/// <summary>
/// Simple authorization filter for Hangfire Dashboard
/// </summary>
public class HangfireAuthorizationFilter : IDashboardAuthorizationFilter
{
    public bool Authorize(DashboardContext context)
    {
        // TODO: Implement proper authorization check
        // For now, allow all in development
        return true;
    }
}
