using Dapper;
using SIGCM.Domain.Entities;
using SIGCM.Domain.Interfaces;
using SIGCM.Infrastructure.Data;

namespace SIGCM.Infrastructure.Repositories;

public class UserRepository : IUserRepository
{
    private readonly IDbConnectionFactory _connectionFactory;

    public UserRepository(IDbConnectionFactory connectionFactory)
    {
        _connectionFactory = connectionFactory;
    }

    // Busca usuario por nombre de usuario
    public async Task<User?> GetByUsernameAsync(string username)
    {
        using var conn = _connectionFactory.CreateConnection();
        return await conn.QuerySingleOrDefaultAsync<User>(
            "SELECT * FROM Users WHERE Username = @Username", 
            new { Username = username });
    }

    // Busca usuario por correo electrónico
    public async Task<User?> GetByEmailAsync(string email)
    {
        using var conn = _connectionFactory.CreateConnection();
        return await conn.QuerySingleOrDefaultAsync<User>(
            "SELECT * FROM Users WHERE Email = @Email", 
            new { Email = email });
    }

    // Busca usuario por identificador único de Google
    public async Task<User?> GetByGoogleIdAsync(string googleId)
    {
        using var conn = _connectionFactory.CreateConnection();
        return await conn.QuerySingleOrDefaultAsync<User>(
            "SELECT * FROM Users WHERE GoogleId = @GoogleId", 
            new { GoogleId = googleId });
    }

    // Crea un nuevo usuario en el sistema
    public async Task<int> CreateAsync(User user)
    {
        using var conn = _connectionFactory.CreateConnection();
        var sql = @"
            INSERT INTO Users (Username, PasswordHash, Role, Email, FailedLoginAttempts, LockoutEnd, MustChangePassword, IsActive, LastLogin, GoogleId, IsMfaEnabled, MfaSecret,
                               BillingName, BillingAddress, BillingTaxId, BillingTaxType, ClientId, Phone)
            VALUES (@Username, @PasswordHash, @Role, @Email, @FailedLoginAttempts, @LockoutEnd, @MustChangePassword, @IsActive, @LastLogin, @GoogleId, @IsMfaEnabled, @MfaSecret,
                    @BillingName, @BillingAddress, @BillingTaxId, @BillingTaxType, @ClientId, @Phone);
            SELECT CAST(SCOPE_IDENTITY() as int);";
        return await conn.QuerySingleAsync<int>(sql, user);
    }

    // Obtiene todos los usuarios
    public async Task<IEnumerable<User>> GetAllAsync()
    {
        using var conn = _connectionFactory.CreateConnection();
        return await conn.QueryAsync<User>("SELECT * FROM Users");
    }

    // Obtiene un usuario por su ID
    public async Task<User?> GetByIdAsync(int id)
    {
        using var conn = _connectionFactory.CreateConnection();
        return await conn.QuerySingleOrDefaultAsync<User>("SELECT * FROM Users WHERE Id = @Id", new { Id = id });
    }

    // Actualiza los datos de un usuario existente
    public async Task UpdateAsync(User user)
    {
        using var conn = _connectionFactory.CreateConnection();
        var sql = @"
            UPDATE Users 
            SET Username = @Username, Role = @Role, Email = @Email, PasswordHash = @PasswordHash,
                FailedLoginAttempts = @FailedLoginAttempts, LockoutEnd = @LockoutEnd, 
                MustChangePassword = @MustChangePassword, IsActive = @IsActive, LastLogin = @LastLogin,
                GoogleId = @GoogleId, IsMfaEnabled = @IsMfaEnabled, MfaSecret = @MfaSecret,
                BillingName = @BillingName, BillingAddress = @BillingAddress, BillingTaxId = @BillingTaxId, BillingTaxType = @BillingTaxType,
                ClientId = @ClientId, Phone = @Phone
            WHERE Id = @Id";
        await conn.ExecuteAsync(sql, user);
    }

    // Elimina un usuario por su ID
    public async Task DeleteAsync(int id)
    {
         using var conn = _connectionFactory.CreateConnection();
         await conn.ExecuteAsync("DELETE FROM Users WHERE Id = @Id", new { Id = id });
    }
}
