using Intentor.Models;
using Microsoft.EntityFrameworkCore;

namespace Intentor.Data;

public sealed class IntentRepository(IntentorDbContext db) : IIntentRepository
{
    public Task<List<Intent>> GetAllAsync(CancellationToken ct = default) =>
        db.Intents
            .AsNoTracking()
            .OrderByDescending(i => i.Priority)
            .ThenBy(i => i.Name)
            .ToListAsync(ct);

    public Task<Intent?> GetByIdAsync(int id, CancellationToken ct = default) =>
        db.Intents.FirstOrDefaultAsync(i => i.Id == id, ct);

    public Task<Intent?> GetByIdWithDependenciesAsync(int id, CancellationToken ct = default) =>
        db.Intents
            .AsNoTracking()
            .Include(i => i.Requirements)
                .ThenInclude(r => r.RequiredIntent)
            .Include(i => i.RequiredBy)
                .ThenInclude(r => r.Intent)
            .FirstOrDefaultAsync(i => i.Id == id, ct);

    public async Task<Intent> AddAsync(Intent intent, CancellationToken ct = default)
    {
        db.Intents.Add(intent);
        await db.SaveChangesAsync(ct);
        return intent;
    }

    public async Task UpdateAsync(Intent intent, CancellationToken ct = default)
    {
        db.Intents.Update(intent);
        await db.SaveChangesAsync(ct);
    }

    public async Task DeleteAsync(int id, CancellationToken ct = default)
    {
        var entity = await db.Intents.FirstOrDefaultAsync(i => i.Id == id, ct);
        if (entity is null) return;

        db.Intents.Remove(entity);
        await db.SaveChangesAsync(ct);
    }

    public async Task SetRequirementsAsync(int intentId, IEnumerable<int> requiredIntentIds, CancellationToken ct = default)
    {
        var distinctIds = requiredIntentIds
            .Where(x => x > 0)
            .Distinct()
            .ToList();

        // Prevent self-dependency
        distinctIds.Remove(intentId);

        // Replace existing requirements
        var existing = await db.IntentRequirements
            .Where(r => r.IntentId == intentId)
            .ToListAsync(ct);

        db.IntentRequirements.RemoveRange(existing);

        foreach (var requiredId in distinctIds)
        {
            db.IntentRequirements.Add(new IntentRequirement
            {
                IntentId = intentId,
                RequiredIntentId = requiredId
            });
        }

        await db.SaveChangesAsync(ct);
    }
}
