using Microsoft.EntityFrameworkCore;
using FacebookService.Domain.AggregatesModel.ChatbotAggregate;
using FacebookService.Domain.SeedWork;

namespace FacebookService.Infrastructure.Repositories;

/// <summary>
/// EN: Repository implementation for ChatbotFlow aggregate.
/// VI: Triển khai repository cho ChatbotFlow aggregate.
/// </summary>
public class ChatbotFlowRepository : IChatbotFlowRepository
{
    private readonly FacebookServiceContext _context;

    public IUnitOfWork UnitOfWork => _context;

    public ChatbotFlowRepository(FacebookServiceContext context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }

    /// <inheritdoc/>
    public async Task<ChatbotFlow?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
    {
        return await _context.ChatbotFlows
            .Include(f => f.TriggerType)
            .FirstOrDefaultAsync(f => f.Id == id, cancellationToken);
    }

    /// <inheritdoc/>
    public async Task<ChatbotFlow?> GetByIdWithNodesAsync(Guid id, CancellationToken cancellationToken = default)
    {
        return await _context.ChatbotFlows
            .Include(f => f.TriggerType)
            .Include(f => f.Nodes)
                .ThenInclude(n => n.NodeType)
            .FirstOrDefaultAsync(f => f.Id == id, cancellationToken);
    }

    /// <inheritdoc/>
    public async Task<IReadOnlyList<ChatbotFlow>> GetByShopIdAsync(Guid shopId, CancellationToken cancellationToken = default)
    {
        return await _context.ChatbotFlows
            .Include(f => f.TriggerType)
            .Where(f => EF.Property<Guid>(f, "_shopId") == shopId)
            .OrderByDescending(f => EF.Property<DateTime>(f, "_createdAt"))
            .ToListAsync(cancellationToken);
    }

    /// <inheritdoc/>
    public async Task<ChatbotFlow?> FindActiveByTriggerAsync(
        Guid shopId,
        FlowTriggerType triggerType,
        string triggerValue,
        CancellationToken cancellationToken = default)
    {
        return await _context.ChatbotFlows
            .Include(f => f.TriggerType)
            .Include(f => f.Nodes)
                .ThenInclude(n => n.NodeType)
            .FirstOrDefaultAsync(f => 
                EF.Property<Guid>(f, "_shopId") == shopId &&
                EF.Property<bool>(f, "_isActive") == true &&
                f.TriggerTypeId == triggerType.Id &&
                EF.Property<string>(f, "_triggerValue") == triggerValue, 
                cancellationToken);
    }

    /// <inheritdoc/>
    public async Task<bool> ExistsByTriggerValueAsync(
        Guid shopId,
        string triggerValue,
        Guid? excludeFlowId = null,
        CancellationToken cancellationToken = default)
    {
        var query = _context.ChatbotFlows
            .Where(f => 
                EF.Property<Guid>(f, "_shopId") == shopId &&
                EF.Property<string>(f, "_triggerValue") == triggerValue);

        if (excludeFlowId.HasValue)
        {
            query = query.Where(f => f.Id != excludeFlowId.Value);
        }

        return await query.AnyAsync(cancellationToken);
    }

    /// <inheritdoc/>
    public ChatbotFlow Add(ChatbotFlow flow)
    {
        return _context.ChatbotFlows.Add(flow).Entity;
    }

    /// <inheritdoc/>
    public void Update(ChatbotFlow flow)
    {
        _context.Entry(flow).State = EntityState.Modified;
    }

    /// <inheritdoc/>
    public void Delete(ChatbotFlow flow)
    {
        _context.ChatbotFlows.Remove(flow);
    }
}
