using Microsoft.EntityFrameworkCore;
using OmsorgCore.Application.Abstractions;
using OmsorgCore.Domain.Entities;
using OmsorgCore.Infrastructure.Persistence;

namespace OmsorgCore.Infrastructure.Repositories;

public class ValueListRepository : IValueListRepository
{
    private readonly OmsorgCoreDbContext _db;

    public ValueListRepository(OmsorgCoreDbContext db)
    {
        _db = db;
    }

    public async Task<IReadOnlyList<ValueList>> GetAllListsAsync(CancellationToken cancellationToken = default)
        => await _db.ValueLists.AsNoTracking().OrderBy(l => l.DisplayName).ToListAsync(cancellationToken);

    public Task<ValueList?> GetListByKeyAsync(string key, CancellationToken cancellationToken = default)
        => _db.ValueLists.AsNoTracking().FirstOrDefaultAsync(l => l.Key == key, cancellationToken);

    public async Task<IReadOnlyList<ValueListItem>> GetItemsAsync(string key, CancellationToken cancellationToken = default)
        => await _db.ValueListItems.AsNoTracking()
            .Where(i => i.ValueList.Key == key)
            .OrderBy(i => i.SortOrder)
            .ToListAsync(cancellationToken);

    public async Task<IReadOnlyList<string>> GetActiveValuesAsync(string key, CancellationToken cancellationToken = default)
        => await _db.ValueListItems.AsNoTracking()
            .Where(i => i.ValueList.Key == key)
            .OrderBy(i => i.SortOrder)
            .Select(i => i.Value)
            .ToListAsync(cancellationToken);

    public Task<ValueListItem?> GetItemByIdAsync(Guid id, CancellationToken cancellationToken = default)
        => _db.ValueListItems.Include(i => i.ValueList).FirstOrDefaultAsync(i => i.Id == id, cancellationToken);

    public Task<ValueListItem?> GetInitialItemAsync(string key, CancellationToken cancellationToken = default)
        => _db.ValueListItems.AsNoTracking().FirstOrDefaultAsync(i => i.ValueList.Key == key && i.IsInitial, cancellationToken);

    public async Task AddItemAsync(ValueListItem item, CancellationToken cancellationToken = default)
        => await _db.ValueListItems.AddAsync(item, cancellationToken);

    public Task UpdateItemAsync(ValueListItem item, CancellationToken cancellationToken = default)
    {
        _db.ValueListItems.Update(item);
        return Task.CompletedTask;
    }

    public Task RemoveItemAsync(ValueListItem item, CancellationToken cancellationToken = default)
    {
        _db.ValueListItems.Remove(item);
        return Task.CompletedTask;
    }

    public async Task<bool> CanTransitionAsync(Guid fromItemId, Guid toItemId, CancellationToken cancellationToken = default)
    {
        if (fromItemId == toItemId)
        {
            return true;
        }

        return await _db.ValueListItemTransitions.AsNoTracking()
            .AnyAsync(t => t.FromItemId == fromItemId && t.ToItemId == toItemId, cancellationToken);
    }

    public async Task<IReadOnlyList<ValueListItemTransition>> GetTransitionsAsync(string key, CancellationToken cancellationToken = default)
        => await _db.ValueListItemTransitions.AsNoTracking()
            .Where(t => t.FromItem.ValueList.Key == key)
            .ToListAsync(cancellationToken);

    public async Task ReplaceTransitionsAsync(string key, IEnumerable<(Guid FromItemId, Guid ToItemId)> transitions, CancellationToken cancellationToken = default)
    {
        var existing = await _db.ValueListItemTransitions
            .Where(t => t.FromItem.ValueList.Key == key)
            .ToListAsync(cancellationToken);
        _db.ValueListItemTransitions.RemoveRange(existing);

        foreach (var (fromItemId, toItemId) in transitions)
        {
            _db.ValueListItemTransitions.Add(new ValueListItemTransition { FromItemId = fromItemId, ToItemId = toItemId });
        }
    }

    public Task<ValueListItemTransition?> GetSelfServiceTransitionAsync(Guid fromItemId, CancellationToken cancellationToken = default)
        => _db.ValueListItemTransitions.AsNoTracking()
            .FirstOrDefaultAsync(t => t.FromItemId == fromItemId && !t.RequiresApproval, cancellationToken);

    public Task<ValueListItemTransition?> GetTransitionAsync(Guid fromItemId, Guid toItemId, CancellationToken cancellationToken = default)
        => _db.ValueListItemTransitions.AsNoTracking()
            .FirstOrDefaultAsync(t => t.FromItemId == fromItemId && t.ToItemId == toItemId, cancellationToken);

    public Task SaveChangesAsync(CancellationToken cancellationToken = default)
        => _db.SaveChangesAsync(cancellationToken);
}
