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

namespace SIGCM.Infrastructure.Repositories;

public class ClientRepository
{
  private readonly IDbConnectionFactory _db;

  public ClientRepository(IDbConnectionFactory db)
  {
    _db = db;
  }

  // Búsqueda inteligente redireccionada a Users
  public async Task<IEnumerable<Client>> SearchAsync(string query)
  {
    using var conn = _db.CreateConnection();
    var sql = @"
            SELECT TOP 10 
                Id, 
                ISNULL(BillingName, Username) as Name, 
                ISNULL(BillingTaxId, '') as DniOrCuit,
                Email, Phone, BillingAddress as Address
            FROM Users 
            WHERE BillingName LIKE @Query OR BillingTaxId LIKE @Query OR Username LIKE @Query
            ORDER BY BillingName";
    return await conn.QueryAsync<Client>(sql, new { Query = $"%{query}%" });
  }

  // Asegurar existencia (Upsert en la tabla Users)
  public async Task<int> EnsureClientExistsAsync(string name, string dni)
  {
    using var conn = _db.CreateConnection();

    var existingId = await conn.ExecuteScalarAsync<int?>(
        "SELECT Id FROM Users WHERE BillingTaxId = @Dni", new { Dni = dni });

    if (existingId.HasValue)
    {
      await conn.ExecuteAsync("UPDATE Users SET BillingName = @Name WHERE Id = @Id", new { Name = name, Id = existingId });
      return existingId.Value;
    }
    else
    {
      // Si no existe, creamos un usuario con rol Cliente (sin password por ahora, es solo para gestión de mostrador)
      var sql = @"
                INSERT INTO Users (Username, Role, BillingName, BillingTaxId, PasswordHash, MustChangePassword) 
                VALUES (@Username, 'Client', @Name, @Dni, 'N/A', 0);
                SELECT CAST(SCOPE_IDENTITY() as int);";
      // El username será el DNI para asegurar unicidad si no hay otro dato
      return await conn.QuerySingleAsync<int>(sql, new { Username = dni, Name = name, Dni = dni });
    }
  }

  // Obtener todos con estadísticas desde Users
  public async Task<IEnumerable<dynamic>> GetAllWithStatsAsync()
  {
    using var conn = _db.CreateConnection();
    var sql = @"
        SELECT 
            u.Id as id, 
            ISNULL(u.BillingName, u.Username) as name, 
            ISNULL(u.BillingTaxId, 'S/D') as dniOrCuit,
            ISNULL(u.Email, 'Sin correo') as email, 
            ISNULL(u.Phone, 'Sin teléfono') as phone,
            (SELECT COUNT(1) FROM Listings l WHERE l.ClientId = u.Id) as totalAds,
            ISNULL((SELECT SUM(AdFee) FROM Listings l WHERE l.ClientId = u.Id), 0) as totalSpent
        FROM Users u
        WHERE Role IN ('Client', 'User') -- Mostramos tanto clientes puros como usuarios web
        ORDER BY name";
    return await conn.QueryAsync(sql);
  }

  public async Task UpdateAsync(Client client)
  {
    using var conn = _db.CreateConnection();
    var sql = @"
        UPDATE Users 
        SET BillingName = @Name, 
            BillingTaxId = @DniOrCuit, 
            Email = @Email, 
            Phone = @Phone, 
            BillingAddress = @Address
        WHERE Id = @Id";
    await conn.ExecuteAsync(sql, client);
  }

  public async Task<dynamic?> GetClientSummaryAsync(int clientId)
  {
    using var conn = _db.CreateConnection();
    var sql = @"
        SELECT 
            u.Id, 
            ISNULL(u.BillingName, u.Username) as Name, 
            u.BillingTaxId as DniOrCuit, u.Email, u.Phone, u.BillingAddress as Address,
            (SELECT COUNT(1) FROM Listings WHERE ClientId = u.Id) as TotalAds,
            ISNULL((SELECT SUM(AdFee) FROM Listings WHERE ClientId = u.Id), 0) as TotalInvested,
            (SELECT MAX(CreatedAt) FROM Listings WHERE ClientId = u.Id) as LastAdDate,
            (SELECT COUNT(1) FROM Listings WHERE ClientId = u.Id AND Status = 'Published') as ActiveAds,
            ISNULL((
                SELECT TOP 1 cat.Name 
                FROM Listings l 
                JOIN Categories cat ON l.CategoryId = cat.Id 
                WHERE l.ClientId = u.Id 
                GROUP BY cat.Name 
                ORDER BY COUNT(l.Id) DESC
            ), 'N/A') as PreferredCategory
        FROM Users u
        WHERE u.Id = @Id";

    return await conn.QuerySingleOrDefaultAsync<dynamic>(sql, new { Id = clientId });
  }
}