using Books.Api.EventFlow.ReadModels;
using Dapper;
using Npgsql;

namespace Books.Api.EventFlow.Repositories;

public class AttachmentRepository(NpgsqlDataSource dataSource) : IAttachmentRepository
{
    private const string SelectColumns = """
        aggregate_id AS Id,
        company_id AS CompanyId,
        file_name AS FileName,
        original_file_name AS OriginalFileName,
        content_type AS ContentType,
        file_size AS FileSize,
        storage_path AS StoragePath,
        uploaded_by AS UploadedBy,
        uploaded_at AS UploadedAt,
        draft_id AS DraftId,
        transaction_id AS TransactionId,
        retention_end_date AS RetentionEndDate,
        is_deleted AS IsDeleted
        """;

    public async Task<AttachmentReadModelDto?> GetByIdAsync(string id, CancellationToken cancellationToken = default)
    {
        await using var connection = await dataSource.OpenConnectionAsync(cancellationToken);

        var sql = $"""
            SELECT {SelectColumns}
            FROM attachment_read_models
            WHERE aggregate_id = @Id AND is_deleted = FALSE
            """;

        return await connection.QuerySingleOrDefaultAsync<AttachmentReadModelDto>(sql, new { Id = id });
    }

    public async Task<IReadOnlyList<AttachmentReadModelDto>> GetByCompanyIdAsync(string companyId, CancellationToken cancellationToken = default)
    {
        await using var connection = await dataSource.OpenConnectionAsync(cancellationToken);

        var sql = $"""
            SELECT {SelectColumns}
            FROM attachment_read_models
            WHERE company_id = @CompanyId AND is_deleted = FALSE
            ORDER BY uploaded_at DESC
            """;

        var result = await connection.QueryAsync<AttachmentReadModelDto>(sql, new { CompanyId = companyId });
        return result.ToList();
    }

    public async Task<IReadOnlyList<AttachmentReadModelDto>> GetByDraftIdAsync(string draftId, CancellationToken cancellationToken = default)
    {
        await using var connection = await dataSource.OpenConnectionAsync(cancellationToken);

        var sql = $"""
            SELECT {SelectColumns}
            FROM attachment_read_models
            WHERE draft_id = @DraftId AND is_deleted = FALSE
            ORDER BY uploaded_at ASC
            """;

        var result = await connection.QueryAsync<AttachmentReadModelDto>(sql, new { DraftId = draftId });
        return result.ToList();
    }

    public async Task<IReadOnlyList<AttachmentReadModelDto>> GetByTransactionIdAsync(string transactionId, CancellationToken cancellationToken = default)
    {
        await using var connection = await dataSource.OpenConnectionAsync(cancellationToken);

        var sql = $"""
            SELECT {SelectColumns}
            FROM attachment_read_models
            WHERE transaction_id = @TransactionId AND is_deleted = FALSE
            ORDER BY uploaded_at ASC
            """;

        var result = await connection.QueryAsync<AttachmentReadModelDto>(sql, new { TransactionId = transactionId });
        return result.ToList();
    }

    public async Task<IReadOnlyList<AttachmentReadModelDto>> GetByIdsAsync(IEnumerable<string> ids, CancellationToken cancellationToken = default)
    {
        await using var connection = await dataSource.OpenConnectionAsync(cancellationToken);

        var sql = $"""
            SELECT {SelectColumns}
            FROM attachment_read_models
            WHERE aggregate_id = ANY(@Ids) AND is_deleted = FALSE
            ORDER BY uploaded_at ASC
            """;

        var result = await connection.QueryAsync<AttachmentReadModelDto>(sql, new { Ids = ids.ToArray() });
        return result.ToList();
    }
}
