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

namespace SIGCM.Infrastructure.Repositories;

public class CategoryRepository : ICategoryRepository
{
    private readonly IDbConnectionFactory _connectionFactory;

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

    public async Task<IEnumerable<Category>> GetAllAsync()
    {
        using var conn = _connectionFactory.CreateConnection();
        return await conn.QueryAsync<Category>("SELECT * FROM Categories");
    }

    public async Task<Category?> GetByIdAsync(int id)
    {
        using var conn = _connectionFactory.CreateConnection();
        return await conn.QueryFirstOrDefaultAsync<Category>("SELECT * FROM Categories WHERE Id = @Id", new { Id = id });
    }

    public async Task<int> AddAsync(Category category)
    {
        using var conn = _connectionFactory.CreateConnection();
        var sql = @"
            INSERT INTO Categories (ParentId, Name, Slug, Active)
            VALUES (@ParentId, @Name, @Slug, @Active);
            SELECT CAST(SCOPE_IDENTITY() as int);";
        return await conn.QuerySingleAsync<int>(sql, category);
    }

    public async Task UpdateAsync(Category category)
    {
        using var conn = _connectionFactory.CreateConnection();
        var sql = @"
            UPDATE Categories 
            SET ParentId = @ParentId, Name = @Name, Slug = @Slug, Active = @Active
            WHERE Id = @Id";
        await conn.ExecuteAsync(sql, category);
    }

    public async Task DeleteAsync(int id)
    {
        using var conn = _connectionFactory.CreateConnection();
        await conn.ExecuteAsync("DELETE FROM Categories WHERE Id = @Id", new { Id = id });
    }

    public async Task<IEnumerable<Category>> GetSubCategoriesAsync(int parentId)
    {
        using var conn = _connectionFactory.CreateConnection();
        return await conn.QueryAsync<Category>("SELECT * FROM Categories WHERE ParentId = @ParentId", new { ParentId = parentId });
    }

    public async Task<IEnumerable<Operation>> GetOperationsAsync(int categoryId)
    {
        using var conn = _connectionFactory.CreateConnection();
        var sql = @"
            SELECT o.* 
            FROM Operations o
            INNER JOIN CategoryOperations co ON o.Id = co.OperationId
            WHERE co.CategoryId = @CategoryId";
        return await conn.QueryAsync<Operation>(sql, new { CategoryId = categoryId });
    }

    public async Task AddOperationAsync(int categoryId, int operationId)
    {
        using var conn = _connectionFactory.CreateConnection();
        var sql = "INSERT INTO CategoryOperations (CategoryId, OperationId) VALUES (@CategoryId, @OperationId)";
        try
        {
            await conn.ExecuteAsync(sql, new { CategoryId = categoryId, OperationId = operationId });
        }
        catch (SqlException)
        {
            // Ignore duplicate key errors if it already exists
        }
    }

    public async Task RemoveOperationAsync(int categoryId, int operationId)
    {
        using var conn = _connectionFactory.CreateConnection();
        await conn.ExecuteAsync(
            "DELETE FROM CategoryOperations WHERE CategoryId = @CategoryId AND OperationId = @OperationId",
            new { CategoryId = categoryId, OperationId = operationId });
    }

    public async Task MergeCategoriesAsync(int sourceId, int targetId)
    {
        using var conn = _connectionFactory.CreateConnection();
        conn.Open();
        using var transaction = conn.BeginTransaction();

        try
        {
            // 1. Mover Avisos
            await conn.ExecuteAsync(
                "UPDATE Listings SET CategoryId = @TargetId WHERE CategoryId = @SourceId",
                new { SourceId = sourceId, TargetId = targetId }, transaction);

            // 2. Mover Subcategorías (Hijos)
            await conn.ExecuteAsync(
                "UPDATE Categories SET ParentId = @TargetId WHERE ParentId = @SourceId",
                new { SourceId = sourceId, TargetId = targetId }, transaction);

            // 3. Mover Definiciones de Atributos
            await conn.ExecuteAsync(
                "UPDATE AttributeDefinitions SET CategoryId = @TargetId WHERE CategoryId = @SourceId",
                new { SourceId = sourceId, TargetId = targetId }, transaction);

            // 4. Mover Operaciones (evitar duplicados con try/catch o lógica compleja, aquí simplificamos moviendo y borrando)
            // Borramos las del source de la tabla intermedia
            await conn.ExecuteAsync(
                "DELETE FROM CategoryOperations WHERE CategoryId = @SourceId",
                new { SourceId = sourceId }, transaction);

            // 5. Borrar Categoría Fuente
            await conn.ExecuteAsync(
                "DELETE FROM Categories WHERE Id = @SourceId",
                new { SourceId = sourceId }, transaction);

            transaction.Commit();
        }
        catch
        {
            transaction.Rollback();
            throw;
        }
    }

    public async Task<bool> HasChildrenAsync(int categoryId)
    {
        using var conn = _connectionFactory.CreateConnection();
        // SELECT 1 es más rápido que COUNT
        var result = await conn.ExecuteScalarAsync<int?>("SELECT TOP 1 1 FROM Categories WHERE ParentId = @Id", new { Id = categoryId });
        return result.HasValue;
    }
}

