using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using MktXService.Domain.AggregatesModel.AIConversationSessionAggregate;
using MktXService.Domain.AggregatesModel.AutomationFlowAggregate;
using MktXService.Domain.AggregatesModel.CampaignAggregate;
using MktXService.Domain.AggregatesModel.ContactAggregate;
using MktXService.Domain.AggregatesModel.ConversationAggregate;
using MktXService.Domain.AggregatesModel.SampleAggregate;
using MktXService.Domain.AggregatesModel.SegmentAggregate;
using MktXService.Domain.AggregatesModel.TemplateAggregate;
using MktXService.Domain.AggregatesModel.TwitterAccountAggregate;
using MktXService.Domain.SeedWork;

namespace MktXService.Infrastructure;

/// <summary>
/// EN: EF Core DbContext for MktXService with PostgreSQL and JSONB support.
/// VI: EF Core DbContext cho MktXService với PostgreSQL và hỗ trợ JSONB.
/// </summary>
/// <remarks>
/// EN: Uses snake_case naming convention for PostgreSQL compatibility.
/// VI: Sử dụng quy ước đặt tên snake_case cho tương thích PostgreSQL.
/// </remarks>
public class MktXServiceContext : DbContext, IUnitOfWork
{
    private readonly IMediator _mediator;
    private IDbContextTransaction? _currentTransaction;

    #region DbSets

    // EN: Sample aggregate (template reference)
    // VI: Sample aggregate (tham chiếu template)
    public DbSet<Sample> Samples => Set<Sample>();
    public DbSet<SampleStatus> SampleStatuses => Set<SampleStatus>();

    // EN: Twitter Account aggregate
    // VI: Aggregate tài khoản Twitter
    public DbSet<TwitterAccount> TwitterAccounts => Set<TwitterAccount>();
    public DbSet<TwitterAccountStatus> TwitterAccountStatuses => Set<TwitterAccountStatus>();

    // EN: Contact aggregate
    // VI: Aggregate liên hệ
    public DbSet<Contact> Contacts => Set<Contact>();
    public DbSet<ContactTag> ContactTags => Set<ContactTag>();

    // EN: Conversation aggregate
    // VI: Aggregate hội thoại
    public DbSet<Conversation> Conversations => Set<Conversation>();
    public DbSet<ConversationStatus> ConversationStatuses => Set<ConversationStatus>();
    public DbSet<Message> Messages => Set<Message>();

    // EN: Template aggregate
    // VI: Aggregate mẫu tin
    public DbSet<Template> Templates => Set<Template>();

    // EN: Campaign aggregate
    // VI: Aggregate chiến dịch
    public DbSet<Campaign> Campaigns => Set<Campaign>();
    public DbSet<CampaignStatus> CampaignStatuses => Set<CampaignStatus>();

    // EN: Segment aggregate
    // VI: Aggregate phân khúc
    public DbSet<Segment> Segments => Set<Segment>();
    public DbSet<SegmentCondition> SegmentConditions => Set<SegmentCondition>();

    // EN: Automation Flow aggregate
    // VI: Aggregate luồng tự động
    public DbSet<AutomationFlow> AutomationFlows => Set<AutomationFlow>();
    public DbSet<FlowStatus> FlowStatuses => Set<FlowStatus>();
    public DbSet<FlowNode> FlowNodes => Set<FlowNode>();
    public DbSet<FlowConnection> FlowConnections => Set<FlowConnection>();

    // EN: AI Conversation Session aggregate
    // VI: Aggregate phiên hội thoại AI
    public DbSet<AIConversationSession> AIConversationSessions => Set<AIConversationSession>();

    #endregion

    /// <summary>
    /// EN: Read-only access to current transaction.
    /// VI: Truy cập chỉ đọc đến transaction hiện tại.
    /// </summary>
    public IDbContextTransaction? CurrentTransaction => _currentTransaction;

    /// <summary>
    /// EN: Check if there is an active transaction.
    /// VI: Kiểm tra xem có transaction đang hoạt động không.
    /// </summary>
    public bool HasActiveTransaction => _currentTransaction != null;

    public MktXServiceContext(DbContextOptions<MktXServiceContext> options) : base(options)
    {
        _mediator = null!;
    }

    public MktXServiceContext(DbContextOptions<MktXServiceContext> options, IMediator mediator) : base(options)
    {
        _mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));

        System.Diagnostics.Debug.WriteLine("MktXServiceContext::ctor - " + GetHashCode());
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // EN: Apply all entity configurations from this assembly
        // VI: Áp dụng tất cả entity configurations từ assembly này
        modelBuilder.ApplyConfigurationsFromAssembly(typeof(MktXServiceContext).Assembly);

        // EN: Configure snake_case naming convention for PostgreSQL
        // VI: Cấu hình quy ước đặt tên snake_case cho PostgreSQL
        // Note: Using Npgsql's built-in SnakeCaseNamingConvention when available
        // For now, we handle it in individual configurations
    }

    /// <summary>
    /// EN: Save entities and dispatch domain events.
    /// VI: Lưu entities và dispatch domain events.
    /// </summary>
    public async Task<bool> SaveEntitiesAsync(CancellationToken cancellationToken = default)
    {
        // EN: Dispatch domain events before saving (side effects)
        // VI: Dispatch domain events trước khi lưu (side effects)
        await DispatchDomainEventsAsync();

        // EN: Save changes to database
        // VI: Lưu thay đổi vào database
        await base.SaveChangesAsync(cancellationToken);

        return true;
    }

    /// <summary>
    /// EN: Begin a new transaction if none is active.
    /// VI: Bắt đầu một transaction mới nếu không có transaction nào đang hoạt động.
    /// </summary>
    public async Task<IDbContextTransaction?> BeginTransactionAsync()
    {
        if (_currentTransaction != null) return null;

        _currentTransaction = await Database.BeginTransactionAsync(System.Data.IsolationLevel.ReadCommitted);

        return _currentTransaction;
    }

    /// <summary>
    /// EN: Commit the current transaction.
    /// VI: Commit transaction hiện tại.
    /// </summary>
    public async Task CommitTransactionAsync(IDbContextTransaction transaction)
    {
        ArgumentNullException.ThrowIfNull(transaction);

        if (transaction != _currentTransaction)
            throw new InvalidOperationException($"Transaction {transaction.TransactionId} is not current");

        try
        {
            await SaveChangesAsync();
            await transaction.CommitAsync();
        }
        catch
        {
            RollbackTransaction();
            throw;
        }
        finally
        {
            if (_currentTransaction != null)
            {
                _currentTransaction.Dispose();
                _currentTransaction = null;
            }
        }
    }

    /// <summary>
    /// EN: Rollback the current transaction.
    /// VI: Rollback transaction hiện tại.
    /// </summary>
    public void RollbackTransaction()
    {
        try
        {
            _currentTransaction?.Rollback();
        }
        finally
        {
            if (_currentTransaction != null)
            {
                _currentTransaction.Dispose();
                _currentTransaction = null;
            }
        }
    }

    /// <summary>
    /// EN: Dispatch all domain events from tracked entities.
    /// VI: Dispatch tất cả domain events từ các entities đang được track.
    /// </summary>
    private async Task DispatchDomainEventsAsync()
    {
        var domainEntities = ChangeTracker
            .Entries<Entity>()
            .Where(x => x.Entity.DomainEvents.Any())
            .ToList();

        var domainEvents = domainEntities
            .SelectMany(x => x.Entity.DomainEvents)
            .ToList();

        domainEntities.ForEach(entity => entity.Entity.ClearDomainEvents());

        foreach (var domainEvent in domainEvents)
        {
            await _mediator.Publish(domainEvent);
        }
    }
}
