namespace TaxBaik.Infrastructure.Repositories;

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

public class CompanyRepository(IDbConnectionFactory connectionFactory) : BaseRepository(connectionFactory), ICompanyRepository
{
    public async Task<int> CreateAsync(Company company, CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        return await conn.QueryFirstAsync<int>(
            @"INSERT INTO companies (company_code, company_name, contact_person, phone, email, memo, is_active, created_at, updated_at)
              VALUES (@CompanyCode, @CompanyName, @ContactPerson, @Phone, @Email, @Memo, @IsActive, NOW(), NOW())
              RETURNING id",
            company);
    }

    public async Task<Company?> GetByIdAsync(int id, CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        return await conn.QueryFirstOrDefaultAsync<Company>(
            @"SELECT id, company_code, company_name, contact_person, phone, email, memo, is_active, created_at, updated_at
              FROM companies WHERE id = @Id",
            new { Id = id });
    }

    public async Task<Company?> GetByCodeAsync(string code, CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        return await conn.QueryFirstOrDefaultAsync<Company>(
            @"SELECT id, company_code, company_name, contact_person, phone, email, memo, is_active, created_at, updated_at
              FROM companies WHERE company_code = @Code",
            new { Code = code });
    }

    public async Task<IEnumerable<Company>> GetAllActiveAsync(CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        return await conn.QueryAsync<Company>(
            @"SELECT id, company_code, company_name, contact_person, phone, email, memo, is_active, created_at, updated_at
              FROM companies WHERE is_active = TRUE ORDER BY company_name");
    }

    public async Task<(IEnumerable<Company> Items, int Total)> GetPagedAsync(int page, int pageSize, CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        var offset = (page - 1) * pageSize;

        using var reader = await conn.QueryMultipleAsync(
            @"SELECT id, company_code, company_name, contact_person, phone, email, memo, is_active, created_at, updated_at
              FROM companies
              ORDER BY company_name
              LIMIT @PageSize OFFSET @Offset;

              SELECT COUNT(*) FROM companies;",
            new { PageSize = pageSize, Offset = offset });

        var items = (await reader.ReadAsync<Company>()).ToList();
        var total = await reader.ReadFirstAsync<int>();

        return (items, total);
    }

    public async Task UpdateAsync(Company company, CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        await conn.ExecuteAsync(
            @"UPDATE companies
              SET company_code = @CompanyCode, company_name = @CompanyName,
                  contact_person = @ContactPerson, phone = @Phone, email = @Email,
                  memo = @Memo, is_active = @IsActive, updated_at = NOW()
              WHERE id = @Id",
            company);
    }

    public async Task DeleteAsync(int id, CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        await conn.ExecuteAsync("DELETE FROM companies WHERE id = @Id", new { Id = id });
    }
}
