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

namespace Books.Api.EventFlow.ReadModels;

[Table("customer_read_models")]
public class CustomerReadModel : IReadModel,
    IAmReadModelFor<CustomerAggregate, CustomerId, CustomerCreatedEvent>,
    IAmReadModelFor<CustomerAggregate, CustomerId, CustomerUpdatedEvent>,
    IAmReadModelFor<CustomerAggregate, CustomerId, CustomerDeactivatedEvent>,
    IAmReadModelFor<CustomerAggregate, CustomerId, CustomerReactivatedEvent>
{
    // 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 CustomerNumber { get; set; } = string.Empty;
    public string CustomerType { get; set; } = string.Empty;
    public string Name { get; set; } = string.Empty;
    public string? Cvr { get; set; }
    public string? Address { get; set; }
    public string? PostalCode { get; set; }
    public string? City { get; set; }
    public string Country { get; set; } = "DK";
    public string? Email { get; set; }
    public string? Phone { get; set; }
    public int PaymentTermsDays { get; set; } = 30;
    public string? DefaultRevenueAccountId { get; set; }
    public string SubLedgerAccountId { get; set; } = string.Empty;
    public bool IsActive { get; set; } = true;

    public Task ApplyAsync(
        IReadModelContext context,
        IDomainEvent<CustomerAggregate, CustomerId, CustomerCreatedEvent> domainEvent,
        CancellationToken cancellationToken)
    {
        var e = domainEvent.AggregateEvent;
        AggregateId = domainEvent.AggregateIdentity.Value;
        CreateTime = domainEvent.Timestamp;
        UpdatedTime = domainEvent.Timestamp;
        LastAggregateSequenceNumber = (int)domainEvent.AggregateSequenceNumber;
        CompanyId = e.CompanyId;
        CustomerNumber = e.CustomerNumber;
        CustomerType = e.CustomerType.ToString();
        Name = e.Name;
        Cvr = e.Cvr;
        Address = e.Address;
        PostalCode = e.PostalCode;
        City = e.City;
        Country = e.Country;
        Email = e.Email;
        Phone = e.Phone;
        PaymentTermsDays = e.PaymentTermsDays;
        DefaultRevenueAccountId = e.DefaultRevenueAccountId;
        SubLedgerAccountId = e.SubLedgerAccountId;
        IsActive = true;
        return Task.CompletedTask;
    }

    public Task ApplyAsync(
        IReadModelContext context,
        IDomainEvent<CustomerAggregate, CustomerId, CustomerUpdatedEvent> domainEvent,
        CancellationToken cancellationToken)
    {
        var e = domainEvent.AggregateEvent;
        UpdatedTime = domainEvent.Timestamp;
        LastAggregateSequenceNumber = (int)domainEvent.AggregateSequenceNumber;
        Name = e.Name;
        Cvr = e.Cvr;
        Address = e.Address;
        PostalCode = e.PostalCode;
        City = e.City;
        Country = e.Country;
        Email = e.Email;
        Phone = e.Phone;
        PaymentTermsDays = e.PaymentTermsDays;
        DefaultRevenueAccountId = e.DefaultRevenueAccountId;
        return Task.CompletedTask;
    }

    public Task ApplyAsync(
        IReadModelContext context,
        IDomainEvent<CustomerAggregate, CustomerId, CustomerDeactivatedEvent> domainEvent,
        CancellationToken cancellationToken)
    {
        UpdatedTime = domainEvent.Timestamp;
        LastAggregateSequenceNumber = (int)domainEvent.AggregateSequenceNumber;
        IsActive = false;
        return Task.CompletedTask;
    }

    public Task ApplyAsync(
        IReadModelContext context,
        IDomainEvent<CustomerAggregate, CustomerId, CustomerReactivatedEvent> domainEvent,
        CancellationToken cancellationToken)
    {
        UpdatedTime = domainEvent.Timestamp;
        LastAggregateSequenceNumber = (int)domainEvent.AggregateSequenceNumber;
        IsActive = true;
        return Task.CompletedTask;
    }
}
