using System.ComponentModel.DataAnnotations.Schema;
using Books.Api.Domain.UserAccess;
using Books.Api.Domain.UserAccess.Events;
using EventFlow.Aggregates;
using EventFlow.PostgreSql.ReadStores.Attributes;
using EventFlow.ReadStores;

namespace Books.Api.EventFlow.ReadModels;

[Table("user_company_access_read_models")]
public class UserCompanyAccessReadModel : IReadModel,
    IAmReadModelFor<UserCompanyAccessAggregate, UserCompanyAccessId, UserCompanyAccessGrantedEvent>,
    IAmReadModelFor<UserCompanyAccessAggregate, UserCompanyAccessId, UserCompanyAccessRoleChangedEvent>,
    IAmReadModelFor<UserCompanyAccessAggregate, UserCompanyAccessId, UserCompanyAccessRevokedEvent>
{
    [PostgreSqlReadModelIdentityColumn]
    public string AggregateId { get; set; } = string.Empty;

    public DateTimeOffset CreateTime { get; set; }
    public DateTimeOffset UpdatedTime { get; set; }

    [PostgreSqlReadModelVersionColumn]
    public int LastAggregateSequenceNumber { get; set; }

    public string UserId { get; set; } = string.Empty;
    public string CompanyId { get; set; } = string.Empty;
    public string Role { get; set; } = string.Empty;
    public string GrantedBy { get; set; } = string.Empty;
    public DateTimeOffset GrantedAt { get; set; }
    public bool IsActive { get; set; } = true;
    public DateTimeOffset? RevokedAt { get; set; }
    public string? RevokedBy { get; set; }

    public Task ApplyAsync(
        IReadModelContext context,
        IDomainEvent<UserCompanyAccessAggregate, UserCompanyAccessId, UserCompanyAccessGrantedEvent> domainEvent,
        CancellationToken cancellationToken)
    {
        var e = domainEvent.AggregateEvent;
        AggregateId = domainEvent.AggregateIdentity.Value;
        CreateTime = domainEvent.Timestamp;
        UpdatedTime = domainEvent.Timestamp;
        LastAggregateSequenceNumber = (int)domainEvent.AggregateSequenceNumber;
        UserId = e.UserId;
        CompanyId = e.CompanyId;
        Role = e.Role.ToDbString();
        GrantedBy = e.GrantedBy;
        GrantedAt = domainEvent.Timestamp;
        IsActive = true;
        RevokedAt = null;
        RevokedBy = null;
        return Task.CompletedTask;
    }

    public Task ApplyAsync(
        IReadModelContext context,
        IDomainEvent<UserCompanyAccessAggregate, UserCompanyAccessId, UserCompanyAccessRoleChangedEvent> domainEvent,
        CancellationToken cancellationToken)
    {
        var e = domainEvent.AggregateEvent;
        UpdatedTime = domainEvent.Timestamp;
        LastAggregateSequenceNumber = (int)domainEvent.AggregateSequenceNumber;
        Role = e.NewRole.ToDbString();
        return Task.CompletedTask;
    }

    public Task ApplyAsync(
        IReadModelContext context,
        IDomainEvent<UserCompanyAccessAggregate, UserCompanyAccessId, UserCompanyAccessRevokedEvent> domainEvent,
        CancellationToken cancellationToken)
    {
        var e = domainEvent.AggregateEvent;
        UpdatedTime = domainEvent.Timestamp;
        LastAggregateSequenceNumber = (int)domainEvent.AggregateSequenceNumber;
        IsActive = false;
        RevokedAt = domainEvent.Timestamp;
        RevokedBy = e.RevokedBy;
        return Task.CompletedTask;
    }
}

public class UserCompanyAccessReadModelLocator : IReadModelLocator
{
    public IEnumerable<string> GetReadModelIds(IDomainEvent domainEvent)
    {
        if (domainEvent.GetAggregateEvent() is IAggregateEvent<UserCompanyAccessAggregate, UserCompanyAccessId>)
        {
            yield return domainEvent.GetIdentity().Value;
        }
    }
}
