using Microsoft.AspNetCore.Mvc;
using QRRapidoApp.Data;
using QRRapidoApp.Models;
using System.Diagnostics;
using System.Security.Claims;

namespace QRRapidoApp.Controllers
{
    /// <summary>
    /// Controller for handling user ratings
    /// </summary>
    [Route("api/ratings")]
    [ApiController]
    public class RatingsController : ControllerBase
    {
        private readonly MongoDbContext _dbContext;
        private readonly ILogger<RatingsController> _logger;

        public RatingsController(MongoDbContext dbContext, ILogger<RatingsController> logger)
        {
            _dbContext = dbContext;
            _logger = logger;
        }

        /// <summary>
        /// Submit a new rating
        /// </summary>
        [HttpPost]
        public async Task<IActionResult> SubmitRating([FromBody] RatingSubmissionDto submission)
        {
            var stopwatch = Stopwatch.StartNew();

            using (_logger.BeginScope(new Dictionary<string, object>
            {
                ["Rating"] = submission.Rating,
                ["HasComment"] = !string.IsNullOrWhiteSpace(submission.Comment)
            }))
            {
                _logger.LogInformation("Rating submission - Rating: {Rating}, HasName: {HasName}, HasEmail: {HasEmail}, HasComment: {HasComment}",
                    submission.Rating, !string.IsNullOrWhiteSpace(submission.Name), !string.IsNullOrWhiteSpace(submission.Email), !string.IsNullOrWhiteSpace(submission.Comment));

                try
                {
                    // Validate rating value
                    if (submission.Rating < 1 || submission.Rating > 5)
                    {
                        _logger.LogWarning("Invalid rating value - Rating: {Rating}", submission.Rating);
                        return BadRequest(new { error = "Rating must be between 1 and 5" });
                    }

                    // Check MongoDB connection
                    if (!_dbContext.IsConnected || _dbContext.Ratings == null)
                    {
                        _logger.LogError("MongoDB not connected or Ratings collection unavailable");
                        return StatusCode(503, new { error = "Database unavailable" });
                    }

                    // Get user ID if authenticated
                    var userId = User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;

                    // Get culture from request
                    var culture = System.Globalization.CultureInfo.CurrentUICulture.Name;

                    // Get IP address
                    var ipAddress = HttpContext.Connection.RemoteIpAddress?.ToString();

                    // Create rating object
                    var rating = new Rating
                    {
                        RatingValue = submission.Rating,
                        Name = submission.Name,
                        Email = submission.Email,
                        Comment = submission.Comment,
                        Url = submission.Url ?? string.Empty,
                        UserAgent = submission.UserAgent ?? string.Empty,
                        UserId = userId,
                        CreatedAt = DateTime.UtcNow,
                        IpAddress = ipAddress,
                        Culture = culture
                    };

                    // Save to MongoDB
                    await _dbContext.Ratings.InsertOneAsync(rating);

                    stopwatch.Stop();
                    _logger.LogInformation("Rating saved successfully - RatingId: {RatingId}, Rating: {Rating}, UserId: {UserId}, ProcessingTime: {ProcessingTimeMs}ms",
                        rating.Id, rating.RatingValue, userId ?? "anonymous", stopwatch.ElapsedMilliseconds);

                    return Ok(new
                    {
                        success = true,
                        message = "Thank you for your feedback!",
                        ratingId = rating.Id
                    });
                }
                catch (Exception ex)
                {
                    stopwatch.Stop();
                    _logger.LogError(ex, "Error saving rating - ProcessingTime: {ProcessingTimeMs}ms",
                        stopwatch.ElapsedMilliseconds);

                    return StatusCode(500, new { error = "Error saving rating" });
                }
            }
        }
    }

    /// <summary>
    /// DTO for rating submission
    /// </summary>
    public class RatingSubmissionDto
    {
        public int Rating { get; set; }
        public string? Name { get; set; }
        public string? Email { get; set; }
        public string? Comment { get; set; }
        public string? Url { get; set; }
        public string? UserAgent { get; set; }
    }
}
