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

namespace Books.Api.EventFlow.ReadModels;

[Table("journal_entry_draft_read_models")]
public class JournalEntryDraftReadModel : IReadModel,
    IAmReadModelFor<JournalEntryDraftAggregate, JournalEntryDraftId, JournalEntryDraftCreatedEvent>,
    IAmReadModelFor<JournalEntryDraftAggregate, JournalEntryDraftId, JournalEntryDraftUpdatedEvent>,
    IAmReadModelFor<JournalEntryDraftAggregate, JournalEntryDraftId, JournalEntryDraftPostedEvent>,
    IAmReadModelFor<JournalEntryDraftAggregate, JournalEntryDraftId, JournalEntryDraftDiscardedEvent>
{
    [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 fields
    public string CompanyId { get; set; } = string.Empty;
    public string Name { get; set; } = string.Empty;
    /// <summary>
    /// Bilagsnummer - unique document number per company (required by Bogføringsloven § 7)
    /// </summary>
    public string VoucherNumber { get; set; } = string.Empty;
    /// <summary>
    /// Bilagsdato - the date of the transaction/document (e.g., invoice date)
    /// </summary>
    public DateTime? DocumentDate { get; set; }
    public string? Description { get; set; }
    public string? FiscalYearId { get; set; }
    /// <summary>
    /// JSON array of posting lines with VAT codes
    /// </summary>
    public string Lines { get; set; } = "[]";
    /// <summary>
    /// JSON array of attachment IDs (bilag references, required by Bogføringsloven § 6)
    /// </summary>
    public string AttachmentIds { get; set; } = "[]";
    public string Status { get; set; } = "active";
    public string? TransactionId { get; set; }
    /// <summary>
    /// The exact timestamp when the draft was posted to the ledger.
    /// </summary>
    public DateTimeOffset? PostedAt { get; set; }
    public string CreatedBy { get; set; } = string.Empty;
    /// <summary>
    /// Full AI extraction data stored as JSON string.
    /// Contains vendor CVR, amounts, VAT, due date, payment reference, line items, etc.
    /// </summary>
    public string? ExtractionData { get; set; }

    public Task ApplyAsync(
        IReadModelContext context,
        IDomainEvent<JournalEntryDraftAggregate, JournalEntryDraftId, JournalEntryDraftCreatedEvent> 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;
        VoucherNumber = e.VoucherNumber;
        CreatedBy = e.CreatedBy;
        Status = "active";
        Lines = "[]";
        AttachmentIds = "[]";
        ExtractionData = e.ExtractionData;

        return Task.CompletedTask;
    }

    public Task ApplyAsync(
        IReadModelContext context,
        IDomainEvent<JournalEntryDraftAggregate, JournalEntryDraftId, JournalEntryDraftUpdatedEvent> domainEvent,
        CancellationToken cancellationToken)
    {
        var e = domainEvent.AggregateEvent;

        UpdatedTime = domainEvent.Timestamp;
        LastAggregateSequenceNumber = (int)domainEvent.AggregateSequenceNumber;

        if (e.Name != null)
            Name = e.Name;

        DocumentDate = e.DocumentDate?.ToDateTime(TimeOnly.MinValue);
        Description = e.Description;
        FiscalYearId = e.FiscalYearId;
        Lines = JsonSerializer.Serialize(e.Lines);
        AttachmentIds = JsonSerializer.Serialize(e.AttachmentIds);

        return Task.CompletedTask;
    }

    public Task ApplyAsync(
        IReadModelContext context,
        IDomainEvent<JournalEntryDraftAggregate, JournalEntryDraftId, JournalEntryDraftPostedEvent> domainEvent,
        CancellationToken cancellationToken)
    {
        UpdatedTime = domainEvent.Timestamp;
        LastAggregateSequenceNumber = (int)domainEvent.AggregateSequenceNumber;

        Status = "posted";
        TransactionId = domainEvent.AggregateEvent.TransactionId;
        PostedAt = domainEvent.AggregateEvent.PostedAt;

        return Task.CompletedTask;
    }

    public Task ApplyAsync(
        IReadModelContext context,
        IDomainEvent<JournalEntryDraftAggregate, JournalEntryDraftId, JournalEntryDraftDiscardedEvent> domainEvent,
        CancellationToken cancellationToken)
    {
        UpdatedTime = domainEvent.Timestamp;
        LastAggregateSequenceNumber = (int)domainEvent.AggregateSequenceNumber;

        Status = "discarded";

        return Task.CompletedTask;
    }
}
