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

namespace Books.Api.EventFlow.ReadModels;

[Table("fiscal_year_read_models")]
public class FiscalYearReadModel : IReadModel,
    IAmReadModelFor<FiscalYearAggregate, FiscalYearId, FiscalYearCreatedEvent>,
    IAmReadModelFor<FiscalYearAggregate, FiscalYearId, FiscalYearClosedEvent>,
    IAmReadModelFor<FiscalYearAggregate, FiscalYearId, FiscalYearReopenedEvent>,
    IAmReadModelFor<FiscalYearAggregate, FiscalYearId, FiscalYearLockedEvent>,
    IAmReadModelFor<FiscalYearAggregate, FiscalYearId, OpeningBalancePostedEvent>
{
    // EventFlow standard columns
    [PostgreSqlReadModelIdentityColumn]
    public string AggregateId { get; set; } = string.Empty;

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

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

    // Business columns
    public string CompanyId { get; set; } = string.Empty;
    public string Name { get; set; } = string.Empty;
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
    public string Status { get; set; } = "open";
    public bool OpeningBalancePosted { get; set; }

    // Audit fields for state transitions
    public DateTimeOffset? ClosingDate { get; set; }
    public string? ClosedBy { get; set; }
    public DateTimeOffset? ReopenedDate { get; set; }
    public string? ReopenedBy { get; set; }
    public DateTimeOffset? LockedDate { get; set; }
    public string? LockedBy { get; set; }

    public Task ApplyAsync(
        IReadModelContext context,
        IDomainEvent<FiscalYearAggregate, FiscalYearId, FiscalYearCreatedEvent> domainEvent,
        CancellationToken cancellationToken)
    {
        var e = domainEvent.AggregateEvent;
        AggregateId = domainEvent.AggregateIdentity.Value;
        CreateTime = domainEvent.Timestamp;
        UpdatedTime = domainEvent.Timestamp;
        LastAggregateSequenceNumber = (int)domainEvent.AggregateSequenceNumber;
        CompanyId = e.CompanyId;
        Name = e.Name;
        StartDate = e.StartDate.ToDateTime(TimeOnly.MinValue);
        EndDate = e.EndDate.ToDateTime(TimeOnly.MinValue);
        Status = "open";
        OpeningBalancePosted = false;
        return Task.CompletedTask;
    }

    public Task ApplyAsync(
        IReadModelContext context,
        IDomainEvent<FiscalYearAggregate, FiscalYearId, FiscalYearClosedEvent> domainEvent,
        CancellationToken cancellationToken)
    {
        var e = domainEvent.AggregateEvent;
        UpdatedTime = domainEvent.Timestamp;
        LastAggregateSequenceNumber = (int)domainEvent.AggregateSequenceNumber;
        Status = "closed";
        ClosingDate = domainEvent.Timestamp;
        ClosedBy = e.ClosedBy;
        return Task.CompletedTask;
    }

    public Task ApplyAsync(
        IReadModelContext context,
        IDomainEvent<FiscalYearAggregate, FiscalYearId, FiscalYearReopenedEvent> domainEvent,
        CancellationToken cancellationToken)
    {
        var e = domainEvent.AggregateEvent;
        UpdatedTime = domainEvent.Timestamp;
        LastAggregateSequenceNumber = (int)domainEvent.AggregateSequenceNumber;
        Status = "open";
        ClosingDate = null;
        ClosedBy = null;
        ReopenedDate = domainEvent.Timestamp;
        ReopenedBy = e.ReopenedBy;
        return Task.CompletedTask;
    }

    public Task ApplyAsync(
        IReadModelContext context,
        IDomainEvent<FiscalYearAggregate, FiscalYearId, FiscalYearLockedEvent> domainEvent,
        CancellationToken cancellationToken)
    {
        var e = domainEvent.AggregateEvent;
        UpdatedTime = domainEvent.Timestamp;
        LastAggregateSequenceNumber = (int)domainEvent.AggregateSequenceNumber;
        Status = "locked";
        LockedDate = domainEvent.Timestamp;
        LockedBy = e.LockedBy;
        return Task.CompletedTask;
    }

    public Task ApplyAsync(
        IReadModelContext context,
        IDomainEvent<FiscalYearAggregate, FiscalYearId, OpeningBalancePostedEvent> domainEvent,
        CancellationToken cancellationToken)
    {
        UpdatedTime = domainEvent.Timestamp;
        LastAggregateSequenceNumber = (int)domainEvent.AggregateSequenceNumber;
        OpeningBalancePosted = true;
        return Task.CompletedTask;
    }
}
