using System.Security.Cryptography;
using System.Text;
using Microsoft.AspNetCore.Mvc;

namespace JobTrackerApi.Controllers
{
    [ApiController]
    [Route("api/client-errors")]
    [RequestSizeLimit(32 * 1024)]
    public class ClientErrorsController : ControllerBase
    {
        private const int MaxFieldLength = 512;
        private const int MaxStackSummaryLength = 1024;

        private readonly ILogger<ClientErrorsController> _logger;

        public ClientErrorsController(ILogger<ClientErrorsController> logger)
        {
            _logger = logger;
        }

        public sealed record ClientErrorReport(
            string? ErrorId,
            string? Message,
            string? Stack,
            string? ComponentStack,
            string? Url,
            string? UserAgent,
            string? At
        );

        [HttpPost]
        public IActionResult Report([FromBody] ClientErrorReport report)
        {
            var errorId = Normalize(report.ErrorId, 128) ?? "unknown";
            var at = Normalize(report.At, 128) ?? "unknown";
            var url = Normalize(report.Url, MaxFieldLength) ?? "unknown";
            var userAgent = Normalize(report.UserAgent, MaxFieldLength) ?? "unknown";
            var message = Normalize(report.Message, MaxFieldLength) ?? "unknown";

            var stackHash = Hash(report.Stack);
            var componentStackHash = Hash(report.ComponentStack);
            var stackPreview = SummarizeStack(report.Stack);
            var componentPreview = SummarizeStack(report.ComponentStack);

            _logger.LogError(
                "ClientError {ErrorId} at {At} url={Url} ua={UserAgent} msg={Message} stackHash={StackHash} componentHash={ComponentStackHash} stackPreview={StackPreview} componentPreview={ComponentPreview}",
                errorId,
                at,
                url,
                userAgent,
                message,
                stackHash,
                componentStackHash,
                stackPreview,
                componentPreview
            );

            return NoContent();
        }

        internal static string? Normalize(string? value, int maxLength)
        {
            if (string.IsNullOrWhiteSpace(value)) return null;

            var normalized = value.Trim().Replace("\r", " ").Replace("\n", " ");
            if (normalized.Length <= maxLength)
            {
                return normalized;
            }

            return normalized[..maxLength];
        }

        internal static string? SummarizeStack(string? value)
        {
            if (string.IsNullOrWhiteSpace(value)) return null;

            var lines = value
                .Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
                .Select(line => line.Replace("\r", string.Empty).Trim())
                .Where(line => line.Length > 0)
                .Take(2)
                .ToArray();

            if (lines.Length == 0) return null;

            var summary = string.Join(" | ", lines);
            return summary.Length <= MaxStackSummaryLength ? summary : summary[..MaxStackSummaryLength];
        }

        internal static string? Hash(string? value)
        {
            if (string.IsNullOrWhiteSpace(value)) return null;

            var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(value));
            return Convert.ToHexString(bytes).ToLowerInvariant();
        }
    }
}
