// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Threading;
using System.Threading.Tasks;
using FloraMultiPlatformFrontend.Application.Exceptions;
using FloraMultiPlatformFrontend.Application.Services.Interfaces;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace FloraMultiPlatformFrontend.Data;

/// <summary>
/// A factory for creating FloraDbContext instances with a dynamically resolved connection string
/// based on the currently selected project.
/// </summary>
public class DynamicDbContextFactory : IDbContextFactory<FloraDbContext>
{
    private readonly IConfigurationService _configurationService;
    private readonly ILogger<DynamicDbContextFactory> _logger;
    private readonly IAuthService _authService;
    private readonly IInfoCenterService _infoCenterService;

    public DynamicDbContextFactory(
        IConfigurationService configurationService,
        ILogger<DynamicDbContextFactory> logger,
        IAuthService authService,
        IInfoCenterService infoCenterService)
    {
        _configurationService = configurationService ?? throw new ArgumentNullException(nameof(configurationService));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        _authService = authService ?? throw new ArgumentNullException(nameof(authService));
        _infoCenterService = infoCenterService ?? throw new ArgumentNullException(nameof(infoCenterService));
    }

    public FloraDbContext CreateDbContext()
    {
        // This method is not typically used with this pattern, but we can provide a basic implementation.
        // The primary logic is in CreateDbContextAsync.
        _logger.LogWarning("Synchronous CreateDbContext called. Consider using CreateDbContextAsync for full dynamic configuration.");
        var context = CreateDbContextAsync().GetAwaiter().GetResult();
        if (context == null)
        {
            throw new InvalidOperationException("Failed to create FloraDbContext instance.");
        }
        return context;
    }

    public async Task<FloraDbContext?> CreateDbContextAsync(CancellationToken cancellationToken = default)
    {
        try
        {
            // Check if user is authenticated before allowing database access
            if (_authService.CurrentAccount == null)
            {
                var message = "Database access requires authentication. Please log in to continue.";
                _logger.LogWarning("CreateDbContextAsync called without authentication");

                throw new NotAuthenticatedException(message);
            }

            // Get the connection string for the currently selected project
            var connectionString = await _configurationService.GetConnectionStringAsync();
            if (string.IsNullOrEmpty(connectionString))
            {
                throw new InvalidOperationException("Connection string could not be retrieved from the current project configuration.");
            }

            // Create a new set of options with the dynamic connection string
            var optionsBuilder = new DbContextOptionsBuilder<FloraDbContext>();
            optionsBuilder.UseSqlServer(connectionString);

            // Enable sensitive data logging for development
            var environment = Environment.GetEnvironmentVariable("AVALONIA_ENVIRONMENT") ?? "Production";
            if (environment.Equals("Development", StringComparison.OrdinalIgnoreCase))
            {
                optionsBuilder.EnableSensitiveDataLogging();
                optionsBuilder.EnableDetailedErrors();
            }

            // Create the context with the new options
            return new FloraDbContext(optionsBuilder.Options, _configurationService);
        }
        catch (NotAuthenticatedException)
        {
            // Re-throw authentication exceptions without additional logging
            throw;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "An error occurred while creating a new FloraDbContext with a dynamic connection string.");
            throw;
        }
    }
}
