namespace TaxBaik.Infrastructure.Repositories;

using Dapper;
using TaxBaik.Domain.Entities;
using TaxBaik.Domain.Interfaces;

public class ContractRepository(IDbConnectionFactory connectionFactory) : BaseRepository(connectionFactory), IContractRepository
{
    public async Task<int> CreateAsync(Contract contract, CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        return await conn.QueryFirstAsync<int>(
            @"INSERT INTO contracts (client_id, contract_number, service_type, contract_date, start_date, end_date, monthly_fee, total_amount, payment_status, status, notes, created_at, updated_at)
              VALUES (@ClientId, @ContractNumber, @ServiceType, @ContractDate, @StartDate, @EndDate, @MonthlyFee, @TotalAmount, @PaymentStatus, @Status, @Notes, NOW(), NOW())
              RETURNING id",
            contract);
    }

    public async Task<IEnumerable<Contract>> GetAllAsync(CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        return await conn.QueryAsync<Contract>(
            @"SELECT id, client_id, contract_number, service_type, contract_date, start_date, end_date, monthly_fee, total_amount, payment_status, status, notes, created_at, updated_at
              FROM contracts ORDER BY contract_date DESC");
    }

    public async Task<Contract?> GetByIdAsync(int id, CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        return await conn.QueryFirstOrDefaultAsync<Contract>(
            @"SELECT id, client_id, contract_number, service_type, contract_date, start_date, end_date, monthly_fee, total_amount, payment_status, status, notes, created_at, updated_at
              FROM contracts WHERE id = @Id",
            new { Id = id });
    }

    public async Task<IEnumerable<Contract>> GetByClientIdAsync(int clientId, CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        return await conn.QueryAsync<Contract>(
            @"SELECT id, client_id, contract_number, service_type, contract_date, start_date, end_date, monthly_fee, total_amount, payment_status, status, notes, created_at, updated_at
              FROM contracts WHERE client_id = @ClientId ORDER BY contract_date DESC",
            new { ClientId = clientId });
    }

    public async Task<IEnumerable<Contract>> GetActiveContractsAsync(CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        return await conn.QueryAsync<Contract>(
            @"SELECT id, client_id, contract_number, service_type, contract_date, start_date, end_date, monthly_fee, total_amount, payment_status, status, notes, created_at, updated_at
              FROM contracts WHERE status = 'active' ORDER BY client_id");
    }

    public async Task<IEnumerable<Contract>> GetExpiringContractsAsync(int daysAhead = 30, CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        return await conn.QueryAsync<Contract>(
            @"SELECT id, client_id, contract_number, service_type, contract_date, start_date, end_date, monthly_fee, total_amount, payment_status, status, notes, created_at, updated_at
              FROM contracts
              WHERE status = 'active' AND end_date IS NOT NULL AND end_date BETWEEN CURRENT_DATE AND CURRENT_DATE + INTERVAL '1 day' * @DaysAhead
              ORDER BY end_date ASC",
            new { DaysAhead = daysAhead });
    }

    public async Task UpdateAsync(Contract contract, CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        await conn.ExecuteAsync(
            @"UPDATE contracts SET contract_number = @ContractNumber, service_type = @ServiceType, contract_date = @ContractDate,
              start_date = @StartDate, end_date = @EndDate, monthly_fee = @MonthlyFee, total_amount = @TotalAmount,
              payment_status = @PaymentStatus, status = @Status, notes = @Notes, updated_at = NOW()
              WHERE id = @Id",
            contract);
    }

    public async Task<decimal> GetMonthlyRecurringRevenueAsync(CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        var result = await conn.QueryFirstAsync<decimal>(
            @"SELECT COALESCE(SUM(monthly_fee), 0) FROM contracts WHERE status = 'active' AND monthly_fee IS NOT NULL");
        return result;
    }
}
