// src/SIGCM.API/Controllers/ListingsController.cs
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SIGCM.Application.DTOs;
using SIGCM.Domain.Entities;
using SIGCM.Domain.Interfaces;
using SIGCM.Infrastructure.Repositories;

namespace SIGCM.API.Controllers;

[ApiController]
[Route("api/[controller]")]
public class ListingsController : ControllerBase
{
    private readonly IListingRepository _repository;
    private readonly ClientRepository _clientRepo;
    private readonly IUserRepository _userRepo;
    private readonly AuditRepository _auditRepo;
    private readonly ICouponRepository _couponRepo;

    public ListingsController(IListingRepository repository, ClientRepository clientRepo, IUserRepository userRepo, AuditRepository auditRepo, ICouponRepository couponRepo)
    {
        _repository = repository;
        _clientRepo = clientRepo;
        _userRepo = userRepo;
        _auditRepo = auditRepo;
        _couponRepo = couponRepo;
    }

    [HttpPost]
    [Authorize]
    public async Task<IActionResult> Create(CreateListingDto dto)
    {
        // SEGURIDAD: Forzamos la obtención del ID desde el Token JWT
        var userIdClaim = User.FindFirst("Id")?.Value;

        // Si por alguna razón el claim no está (configuración de JWT), no permitimos la creación
        if (string.IsNullOrEmpty(userIdClaim) || !int.TryParse(userIdClaim, out int currentUserId))
        {
            return Unauthorized(new { message = "No se pudo identificar al usuario desde el token de seguridad." });
        }

        int? clientId = null;
        var user = await _userRepo.GetByIdAsync(currentUserId);

        // Lógica de Vinculación Usuario-Cliente
        if (user != null)
        {
            clientId = user.ClientId;

            // Si el usuario no tiene cliente vinculado, pero envía datos de facturación (o registramos los que tiene)
            if (clientId == null)
            {
                string? dniToUse = dto.ClientDni ?? user.BillingTaxId;
                if (!string.IsNullOrWhiteSpace(dniToUse))
                {
                    string? nameToUse = dto.ClientName ?? user.BillingName ?? user.Username;
                    clientId = await _clientRepo.EnsureClientExistsAsync(nameToUse!, dniToUse!);
                    
                    // Actualizamos el usuario con su nuevo nexo de cliente
                    user.ClientId = clientId;
                    user.BillingTaxId = dniToUse;
                    user.BillingName = nameToUse;
                    await _userRepo.UpdateAsync(user);
                }
            }
        }

        var listing = new Listing
        {
            CategoryId = dto.CategoryId,
            OperationId = dto.OperationId,
            Title = dto.Title,
            Description = dto.Description,
            Price = dto.Price,
            AdFee = dto.AdFee,
            Currency = "ARS",
            UserId = currentUserId,
            ClientId = clientId,
            Origin = dto.Origin ?? "Web",
            Status = dto.Status,
            ImagesToClone = dto.ImagesToClone,
            CreatedAt = DateTime.UtcNow,
            PrintText = dto.PrintText,
            PrintDaysCount = dto.PrintDaysCount,
            PrintStartDate = dto.PrintStartDate ?? dto.PublicationStartDate,
            IsBold = dto.IsBold,
            IsFrame = dto.IsFrame,
            PrintFontSize = dto.PrintFontSize,
            PrintAlignment = dto.PrintAlignment,
            // Nuevos Campos
            PublicationStartDate = dto.PublicationStartDate,
            IsFeatured = dto.IsFeatured,
            AllowContact = dto.AllowContact,
            CouponCode = dto.CouponCode
        };

        // Validar límite de uso de cupón por usuario
        if (!string.IsNullOrEmpty(dto.CouponCode))
        {
            var coupon = await _couponRepo.GetByCodeAsync(dto.CouponCode);
            if (coupon != null && coupon.MaxUsagesPerUser.HasValue)
            {
                // Contar usos previos
                var userUsageCount = await _couponRepo.CountUserUsageAsync(currentUserId, coupon.Code);
                if (userUsageCount >= coupon.MaxUsagesPerUser.Value)
                {
                    return BadRequest(new { message = $"El cupón {dto.CouponCode} ya ha superado el límite de uso para este usuario." });
                }
            }
        }

        // Lógica de fecha de inicio: Si el usuario solicitó una fecha futura, ApprovedAt permanece null hasta esa fecha.
        // La lógica actual establece ApprovedAt al aprobar en moderación.
        // PublicationStartDate es solo una referencia de solicitud.

        // Conversión de Pagos
        List<Payment>? payments = null;
        if (dto.Payments != null && dto.Payments.Any())
        {
            payments = dto.Payments.Select(p => new Payment
            {
                Amount = p.Amount,
                PaymentMethod = p.PaymentMethod,
                CardPlan = p.CardPlan,
                Surcharge = p.Surcharge,
                PaymentDate = DateTime.UtcNow
            }).ToList();
        }

        var id = await _repository.CreateAsync(listing, dto.Attributes, payments);

        // Coupon Usage Logic
        if (!string.IsNullOrEmpty(dto.CouponCode))
        {
            var coupon = await _couponRepo.GetByCodeAsync(dto.CouponCode);
            if (coupon != null)
            {
                await _couponRepo.IncrementUsageAsync(coupon.Id);
            }
        }

        // Registro de Auditoría
        await _auditRepo.AddLogAsync(new AuditLog
        {
            UserId = currentUserId,
            Action = "CREATE_LISTING",
            EntityId = id,
            EntityType = "Listing",
            Details = $"Aviso creado por usuario autenticado. Total: ${dto.AdFee}. Featured: {dto.IsFeatured}",
            CreatedAt = DateTime.UtcNow
        });

        return Ok(new { id });
    }

    [HttpGet]
    public async Task<IActionResult> GetAll([FromQuery] string? q, [FromQuery] int? categoryId)
    {
        if (string.IsNullOrEmpty(q) && !categoryId.HasValue)
        {
            var listings = await _repository.GetAllAsync();
            return Ok(listings);
        }

        var results = await _repository.SearchAsync(q, categoryId);
        return Ok(results);
    }

    [HttpGet("my")]
    [Authorize]
    public async Task<IActionResult> GetMyListings()
    {
        // SEGURIDAD: Forzamos el ID del usuario desde el Claim
        var userIdStr = User.FindFirst("Id")?.Value;
        if (string.IsNullOrEmpty(userIdStr) || !int.TryParse(userIdStr, out int userId))
            return Unauthorized();

        var listings = await _repository.GetByUserIdAsync(userId);
        return Ok(listings);
    }

    [HttpGet("{id}")]
    public async Task<IActionResult> Get(int id)
    {
        await _repository.IncrementViewCountAsync(id);
        var listingDetail = await _repository.GetDetailByIdAsync(id);
        if (listingDetail == null) return NotFound();
        return Ok(listingDetail);
    }

    [HttpPost("search")]
    public async Task<IActionResult> Search([FromBody] SearchRequest request)
    {
        var results = await _repository.SearchFacetedAsync(
            request.Query,
            request.CategoryId,
            request.Filters,
            request.From,
            request.To,
            request.Origin,
            request.Status,
            request.OnlyActive
        );
        return Ok(results);
    }

    [HttpGet("pending")]
    [Authorize(Roles = "Admin,Moderador")]
    public async Task<IActionResult> GetPending()
    {
        var pending = await _repository.GetPendingModerationAsync();
        return Ok(pending);
    }

    [HttpPut("{id}/status")]
    [Authorize(Roles = "Admin,Moderador")]
    public async Task<IActionResult> UpdateStatus(int id, [FromBody] UpdateStatusRequest request)
    {
        // Obtener el ID de quien realiza la acción (Administrador/Moderador)
        var userIdStr = User.FindFirst("Id")?.Value;
        if (string.IsNullOrEmpty(userIdStr) || !int.TryParse(userIdStr, out int currentUserId))
            return Unauthorized();

        await _repository.UpdateStatusAsync(id, request.Status);

        string actionDetails = $"El usuario {currentUserId} cambió el estado del aviso #{id} a {request.Status}";
        if (!string.IsNullOrEmpty(request.Note))
        {
            actionDetails += $". Nota al usuario: {request.Note}";
            // TODO: Create actual Notification record for user
        }

        await _auditRepo.AddLogAsync(new AuditLog
        {
            UserId = currentUserId,
            Action = request.Status == "Published" ? "APPROVE_LISTING" : "REJECT_LISTING",
            EntityId = id,
            EntityType = "Listing",
            Details = actionDetails,
            CreatedAt = DateTime.UtcNow
        });

        return Ok();
    }

    public class UpdateStatusRequest
    {
        public required string Status { get; set; }
        public string? Note { get; set; }
    }

    public class SearchRequest
    {
        public string? Query { get; set; }
        public int? CategoryId { get; set; }
        public Dictionary<string, string>? Filters { get; set; }
        public DateTime? From { get; set; }
        public DateTime? To { get; set; }
        public string? Origin { get; set; }
        public string? Status { get; set; }
        public bool OnlyActive { get; set; } = false;
    }

    [HttpGet("pending/count")]
    public async Task<IActionResult> GetPendingCount()
    {
        var count = await _repository.GetPendingCountAsync();
        return Ok(count);
    }

    [HttpPatch("{id}/overlay")]
    [Authorize]
    public async Task<IActionResult> UpdateOverlay(int id, [FromBody] string? status)
    {
        var userIdClaim = User.FindFirst("Id")?.Value;
        if (!int.TryParse(userIdClaim, out int userId)) return Unauthorized();

        // Validar estados permitidos
        var allowed = new[] { "Vendido", "Alquilado", "Reservado", null };
        if (!allowed.Contains(status)) return BadRequest("Estado no permitido");

        await _repository.UpdateOverlayStatusAsync(id, userId, status);
        return NoContent();
    }
}