using molilian.core;
using dodohold.core;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json;
using TencentCloud.Ecm.V20190719.Models;
using YunhuiKit;

namespace molilian.api.Controllers
{
    [ApiController]
    [Route("[controller]/[action]")]
    public class TracksController : ControllerBase
    {
        protected IHttpContextAccessor _accessor;
        public TracksController(IHttpContextAccessor accessor)
        {
            _accessor = accessor;
        }

        [HttpGet]
        public async Task<ActionResult> Track([FromQuery] string? track_id = null, [FromQuery] string? unique_id = null, [FromQuery] string? scene = "", [FromQuery] string? account_id = null)
        {
            bool validTrackId = int.TryParse(track_id, out int parsedTrackId) && parsedTrackId > 0;
            int parsedAccountId = 0;
            bool validAccountId = string.IsNullOrWhiteSpace(account_id) || int.TryParse(account_id, out parsedAccountId);
            parsedAccountId = validAccountId ? Math.Max(parsedAccountId, 0) : 0;
            string requestUniqueId = unique_id ?? string.Empty;
            string requestScene = scene ?? string.Empty;

            await WriteTrackRequestTextLogAsync(track_id, unique_id, scene, account_id, parsedTrackId, validTrackId, parsedAccountId, validAccountId);

            if (!validTrackId)
            {
                return new APIResult(new { success = false, message = "miss" });
            }

            var link = await TracksCore.GetLinkByIdAsync(parsedTrackId);
            if (link == null)
            {
                return new APIResult(new { success = false, message = "not found" });
            }

            string trackScene = TracksCore.ResolveMetricScene(link, requestScene);
            var dto = new TrackRequestLogDTO
            {
                track_id = parsedTrackId,
                account_id = parsedAccountId,
                event_type = link.event_type,
                platform = link.platform,
                typename = link.typename,
                scene = trackScene,
                unique_id = requestUniqueId,
                ip = _accessor.HttpContext?.GetUserIp() ?? string.Empty,
                user_agent = Request.Headers.UserAgent.ToString(),
                referer = Request.Headers.Referer.ToString()
            };
            _ = TracksCore.LogTrackRequestAsync(dto);
            _ = TracksCore.TrackAsync(link, trackScene, parsedAccountId);
            return new APIResult(new { success = true, message = "ok" });
        }

        [HttpPost]
        public async Task<ActionResult> Create([FromQuery] string eventType, [FromQuery] string platform = "", [FromQuery] string typename = "", [FromQuery] string scene = "", [FromQuery] string uniqueId = "", [FromQuery] string description = "")
        {
            if (string.IsNullOrWhiteSpace(typename)) typename = platform;
            if (string.IsNullOrWhiteSpace(platform)) platform = typename;
            var link = await TracksCore.CreateLinkAsync(eventType, platform, typename, scene, uniqueId, description);
            if (link == null)
            {
                return new APIResult(new { success = false, message = "invalid params or eventType" });
            }
            //var request = _accessor.HttpContext!.Request;
            //string url = $"{request.Scheme}://{request.Host}{link.path}";
            return new APIResult(new { success = true, message = "ok", url = link.path });
        }

        [HttpGet]
        public async Task<ActionResult> Daily([FromQuery] int daysAgo = 0, [FromQuery] string reportDate = "", [FromQuery] bool includeToday = true, [FromQuery] bool includeYesterday = true)
        {
            var dates = new List<DateTime>();
            DateTime today = DateTime.Now.Date;

            if (!string.IsNullOrWhiteSpace(reportDate) && DateTime.TryParse(reportDate, out var parsed))
            {
                dates.Add(parsed.Date);
                if (includeToday && parsed.Date != today) dates.Add(today);
            }
            else
            {
                if (daysAgo > 0)
                {
                    var date = today.AddDays(-daysAgo);
                    dates.Add(date);
                    if (includeToday && date != today) dates.Add(today);
                }
                else
                {
                    dates.Add(today);
                    if (includeYesterday) dates.Add(today.AddDays(-1));
                }
            }

            int rows = 0;
            var reportDates = new List<string>();
            var details = new List<object>();
            foreach (var date in dates.Distinct())
            {
                int dateRows = await TracksCore.FlushDailyAsync(date);
                rows += dateRows;
                reportDates.Add(date.ToString("yyyy-MM-dd"));
                details.Add(new { reportDate = date.ToString("yyyy-MM-dd"), rows = dateRows });
            }
            return new APIResult(new { success = true, message = "ok", rows, reportDates, details });

        }

        private async Task WriteTrackRequestTextLogAsync(
            string? rawTrackId,
            string? rawUniqueId,
            string? rawScene,
            string? rawAccountId,
            int parsedTrackId,
            bool validTrackId,
            int parsedAccountId,
            bool validAccountId)
        {
            try
            {
                string rawTarget = HttpContext.Features.Get<IHttpRequestFeature>()?.RawTarget ?? $"{Request.Path}{Request.QueryString}";
                string rawQuery = string.Empty;
                int rawQueryIndex = rawTarget.IndexOf('?');
                if (rawQueryIndex >= 0 && rawQueryIndex < rawTarget.Length - 1)
                {
                    rawQuery = rawTarget[(rawQueryIndex + 1)..];
                }

                var logItem = new
                {
                    time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"),
                    method = Request.Method,
                    scheme = Request.Scheme,
                    host = Request.Host.Value,
                    path = Request.Path.Value ?? string.Empty,
                    raw_target = rawTarget,
                    raw_query = rawQuery,
                    raw_query_string = Request.QueryString.Value ?? string.Empty,
                    query = Request.Query.ToDictionary(item => item.Key, item => item.Value.ToArray()),
                    bound = new
                    {
                        track_id = rawTrackId ?? string.Empty,
                        unique_id = rawUniqueId ?? string.Empty,
                        scene = rawScene ?? string.Empty,
                        account_id = rawAccountId ?? string.Empty
                    },
                    parsed = new
                    {
                        track_id = parsedTrackId,
                        track_id_valid = validTrackId,
                        account_id = parsedAccountId,
                        account_id_valid = validAccountId
                    },
                    ip = _accessor.HttpContext?.GetUserIp() ?? string.Empty,
                    remote_ip = HttpContext.Connection.RemoteIpAddress?.ToString() ?? string.Empty,
                    x_forwarded_for = Request.Headers["X-Forwarded-For"].ToString(),
                    x_original_url = Request.Headers["X-Original-URL"].ToString(),
                    x_rewrite_url = Request.Headers["X-Rewrite-URL"].ToString(),
                    user_agent = Request.Headers.UserAgent.ToString(),
                    referer = Request.Headers.Referer.ToString()
                };

                await new LoggerLibrary("tracks", "track_request")
                    .Info(JsonSerializer.Serialize(logItem))
                    .SaveAsync();
            }
            catch (Exception ex)
            {
                _ = new LoggerLibrary("tracks", "track_request_error")
                    .Info(ex.Message, ex.StackTrace)
                    .SaveAsync();
            }
        }
    }
}
