using Npgsql;
using Tiku.Application.Tenancy;
using Tiku.Domain.Tenancy;

namespace Tiku.Infrastructure.Tenancy;

public sealed class TenantDirectory(NpgsqlDataSource dataSource) : ITenantDirectory
{
    public Task<TenantDirectoryEntry?> FindByHostAsync(
        string host,
        CancellationToken cancellationToken = default)
    {
        const string sql = """
            select t.id, t.slug, t.name, t.status, t.mode, d.host
            from tenant_domains d
            join tenants t on t.id = d.tenant_id
            where d.host = @lookup
              and d.status = 'active'
              and t.status = 'active'
            limit 1
            """;
        return FindAsync(sql, host, cancellationToken);
    }

    public Task<TenantDirectoryEntry?> FindByCodeAsync(
        string tenantCode,
        CancellationToken cancellationToken = default)
    {
        const string sql = """
            select t.id, t.slug, t.name, t.status, t.mode, null::text as host
            from tenants t
            where t.slug = @lookup
              and t.status = 'active'
            limit 1
            """;
        return FindAsync(sql, tenantCode, cancellationToken);
    }

    private async Task<TenantDirectoryEntry?> FindAsync(
        string sql,
        string lookup,
        CancellationToken cancellationToken)
    {
        await using var command = dataSource.CreateCommand(sql);
        command.Parameters.AddWithValue("lookup", lookup);
        await using var reader = await command.ExecuteReaderAsync(cancellationToken);
        if (!await reader.ReadAsync(cancellationToken))
        {
            return null;
        }

        return new TenantDirectoryEntry(
            reader.GetGuid(0),
            reader.GetString(1),
            reader.GetString(2),
            ParseEnum<TenantStatus>(reader.GetString(3)),
            ParseEnum<TenantMode>(reader.GetString(4)),
            reader.IsDBNull(5) ? null : reader.GetString(5));
    }

    private static TEnum ParseEnum<TEnum>(string value)
        where TEnum : struct, Enum
    {
        return Enum.Parse<TEnum>(value.Replace("_", string.Empty, StringComparison.Ordinal), true);
    }
}
