using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SIGCM.Domain.Entities;
using SIGCM.Domain.Interfaces;

using SIGCM.Infrastructure.Repositories;

namespace SIGCM.API.Controllers;

[ApiController]
[Route("api/[controller]")]
public class CategoriesController : ControllerBase
{
    private readonly ICategoryRepository _repository;
    private readonly IListingRepository _listingRepo;
    private readonly AuditRepository _auditRepo;

    public CategoriesController(ICategoryRepository repository, IListingRepository listingRepo, AuditRepository auditRepo)
    {
        _repository = repository;
        _listingRepo = listingRepo;
        _auditRepo = auditRepo;
    }

    [HttpGet]
    [AllowAnonymous]
    public async Task<IActionResult> GetAll()
    {
        var categories = await _repository.GetAllAsync();
        return Ok(categories);
    }

    [HttpGet("{id}")]
    [AllowAnonymous]
    public async Task<IActionResult> GetById(int id)
    {
        var category = await _repository.GetByIdAsync(id);
        if (category == null) return NotFound();
        return Ok(category);
    }

    [HttpPost]
    [Authorize(Roles = "Admin")]
    public async Task<IActionResult> Create(Category category)
    {
        // Regla: No crear hijos en padres con avisos
        if (category.ParentId.HasValue)
        {
            int adsCount = await _listingRepo.CountByCategoryIdAsync(category.ParentId.Value);
            if (adsCount > 0)
                return BadRequest($"El rubro padre contiene {adsCount} avisos. Muévalos antes de crear sub-rubros.");
        }

        var id = await _repository.AddAsync(category);
        category.Id = id;

        // Audit Log
        var userIdClaim = User.FindFirst("Id")?.Value;
        if (int.TryParse(userIdClaim, out int userId))
        {
            await _auditRepo.AddLogAsync(new AuditLog
            {
                UserId = userId,
                Action = "CREATE_CATEGORY",
                EntityId = id,
                EntityType = "Category",
                Details = $"Rubro '{category.Name}' creado (Padre ID: {category.ParentId})",
                CreatedAt = DateTime.UtcNow
            });
        }

        return CreatedAtAction(nameof(GetById), new { id }, category);
    }

    [HttpPut("{id}")]
    [Authorize(Roles = "Admin")]
    public async Task<IActionResult> Update(int id, Category category)
    {
        if (id != category.Id) return BadRequest();

        // Regla: Drag & Drop (Mover categoría dentro de otra)
        if (category.ParentId.HasValue)
        {
            int adsCount = await _listingRepo.CountByCategoryIdAsync(category.ParentId.Value);
            if (adsCount > 0)
                return BadRequest($"El destino contiene {adsCount} avisos. No puede aceptar sub-rubros.");
        }

        await _repository.UpdateAsync(category);

        // Audit Log
        var userIdClaim = User.FindFirst("Id")?.Value;
        if (int.TryParse(userIdClaim, out int userId))
        {
            await _auditRepo.AddLogAsync(new AuditLog
            {
                UserId = userId,
                Action = "UPDATE_CATEGORY",
                EntityId = id,
                EntityType = "Category",
                Details = $"Rubro ID #{id} actualizado a '{category.Name}'",
                CreatedAt = DateTime.UtcNow
            });
        }

        return NoContent();
    }

    [HttpDelete("{id}")]
    [Authorize(Roles = "Admin")]
    public async Task<IActionResult> Delete(int id)
    {
        await _repository.DeleteAsync(id);

        // Audit Log
        var userIdClaim = User.FindFirst("Id")?.Value;
        if (int.TryParse(userIdClaim, out int userId))
        {
            await _auditRepo.AddLogAsync(new AuditLog 
            {
                UserId = userId,
                Action = "DELETE_CATEGORY",
                EntityId = id,
                EntityType = "Category",
                Details = "Category deleted via API",
                CreatedAt = DateTime.UtcNow
            });
        }

        return NoContent();
    }

    // --- Endpoints de Operaciones ---
    [HttpGet("{id}/operations")]
    public async Task<IActionResult> GetOperations(int id)
    {
        var operations = await _repository.GetOperationsAsync(id);
        return Ok(operations);
    }

    [HttpPost("{id}/operations/{operationId}")]
    public async Task<IActionResult> AddOperation(int id, int operationId)
    {
        await _repository.AddOperationAsync(id, operationId);
        return Ok();
    }

    [HttpDelete("{id}/operations/{operationId}")]
    public async Task<IActionResult> RemoveOperation(int id, int operationId)
    {
        await _repository.RemoveOperationAsync(id, operationId);
        return NoContent();
    }

    // --- Endpoints Avanzados ---

    [HttpPost("merge")]
    public async Task<IActionResult> Merge([FromBody] MergeRequest request)
    {
        if (request.SourceId == request.TargetId) return BadRequest("Origen y destino iguales.");
        await _repository.MergeCategoriesAsync(request.SourceId, request.TargetId);

        // Audit Log
        var userIdClaim = User.FindFirst("Id")?.Value;
        if (int.TryParse(userIdClaim, out int userId))
        {
            await _auditRepo.AddLogAsync(new AuditLog
            {
                UserId = userId,
                Action = "MERGE_CATEGORIES",
                EntityId = request.TargetId,
                EntityType = "Category",
                Details = $"Rubro ID #{request.SourceId} fusionado en ID #{request.TargetId}",
                CreatedAt = DateTime.UtcNow
            });
        }

        return Ok(new { message = "Fusión completada." });
    }

    [HttpPost("move-content")]
    public async Task<IActionResult> MoveContent([FromBody] MergeRequest request)
    {
        if (request.SourceId == request.TargetId) return BadRequest("Origen y destino iguales.");

        // Regla: No mover avisos a una categoría que tiene hijos (Padre)
        bool targetHasChildren = await _repository.HasChildrenAsync(request.TargetId);
        if (targetHasChildren)
        {
            return BadRequest("El destino tiene sub-rubros. No puede contener avisos directos.");
        }

        await _listingRepo.MoveListingsAsync(request.SourceId, request.TargetId);

        // Audit Log
        var userIdClaim = User.FindFirst("Id")?.Value;
        if (int.TryParse(userIdClaim, out int userId))
        {
            await _auditRepo.AddLogAsync(new AuditLog
            {
                UserId = userId,
                Action = "MOVE_CONTENT",
                EntityId = request.TargetId,
                EntityType = "Listing",
                Details = $"Avisos movidos del Rubro ID #{request.SourceId} al ID #{request.TargetId}",
                CreatedAt = DateTime.UtcNow
            });
        }

        return Ok(new { message = "Avisos movidos correctamente." });
    }

    public class MergeRequest { public int SourceId { get; set; } public int TargetId { get; set; } }
}