using Hc900Crawler.Core.Application.Interfaces;
using Microsoft.AspNetCore.Mvc;

namespace Hc900Crawler.Web.Controllers;

[ApiController]
[Route("api/fast")]
public class FastController : ControllerBase
{
    private readonly IExperionDbService _db;
    private static readonly Dictionary<int, CancellationTokenSource> _sessions = new();

    public FastController(IExperionDbService db) => _db = db;

    [HttpGet("sessions")]
    public async Task<IActionResult> GetSessions()
    {
        var sessions = await _db.GetFastSessionsAsync();
        var items = sessions.Select(s => new
        {
            s.Id, s.Name, s.StartedAt, s.EndedAt, s.Status,
            s.SamplingMs, s.DurationSec, s.RowCount,
            TagCount = string.IsNullOrEmpty(s.TagList) ? 0
                : System.Text.Json.JsonSerializer.Deserialize<string[]>(s.TagList)?.Length ?? 0,
            s.RetentionDays, s.Pinned,
            TagList = string.IsNullOrEmpty(s.TagList)
                ? Array.Empty<string>()
                : System.Text.Json.JsonSerializer.Deserialize<string[]>(s.TagList) ?? Array.Empty<string>()
        });
        return Ok(new { items });
    }

    [HttpGet("{id}")]
    public async Task<IActionResult> GetSession(int id)
    {
        var s = await _db.GetFastSessionAsync(id);
        if (s == null) return NotFound();
        return Ok(new
        {
            s.Id, s.Name, s.StartedAt, s.EndedAt, s.Status,
            s.SamplingMs, s.DurationSec, s.RowCount,
            TagList = string.IsNullOrEmpty(s.TagList)
                ? Array.Empty<string>()
                : System.Text.Json.JsonSerializer.Deserialize<string[]>(s.TagList) ?? Array.Empty<string>(),
            s.RetentionDays, s.Pinned
        });
    }

    [HttpPost("start")]
    public async Task<IActionResult> Start([FromBody] FastSessionCreateRequest req)
    {
        var session = await _db.CreateFastSessionAsync(req);

        var cts = new CancellationTokenSource();
        lock (_sessions) { _sessions[session.Id] = cts; }
        _ = Task.Run(() => RunSessionAsync(session.Id, req, cts.Token));
        return Ok(new { session.Id, status = "Running" });
    }

    private async Task RunSessionAsync(int sessionId, FastSessionCreateRequest req, CancellationToken ct)
    {
        var endAt = DateTime.UtcNow.AddSeconds(req.DurationSec);
        int rowCount = 0;
        try
        {
            while (!ct.IsCancellationRequested && DateTime.UtcNow < endAt)
            {
                var now = DateTime.UtcNow;
                var live = (await _db.GetRealtimeRecordsByTagNamesAsync(req.TagList))
                           .ToDictionary(p => p.TagName, p => p.LiveValue);
                var records = req.TagList.Select(t => new Hc900Crawler.Core.Domain.Entities.FastRecord
                {
                    SessionId  = sessionId,
                    RecordedAt = now,
                    TagName    = t,
                    Value      = live.GetValueOrDefault(t)
                }).ToList();

                await _db.BatchInsertFastRecordsAsync(records);
                rowCount += records.Count;
                await _db.UpdateFastSessionRowCountAsync(sessionId, rowCount);
                await Task.Delay(req.SamplingMs, ct);
            }
            await _db.UpdateFastSessionStatusAsync(sessionId, "Completed");
        }
        catch (OperationCanceledException)
        {
            await _db.UpdateFastSessionStatusAsync(sessionId, "Stopped");
        }
        finally { lock (_sessions) { _sessions.Remove(sessionId); } }
    }

    [HttpPost("{id}/stop")]
    public async Task<IActionResult> Stop(int id)
    {
        lock (_sessions) { if (_sessions.TryGetValue(id, out var cts)) { cts.Cancel(); _sessions.Remove(id); } }
        await _db.UpdateFastSessionStatusAsync(id, "Stopped");
        return Ok(new { success = true });
    }

    [HttpDelete("{id}")]
    public async Task<IActionResult> Delete(int id)
    {
        lock (_sessions) { if (_sessions.TryGetValue(id, out var cts)) { cts.Cancel(); _sessions.Remove(id); } }
        await _db.DeleteFastSessionAsync(id);
        return Ok(new { success = true });
    }

    [HttpPost("{id}/pin")]
    public async Task<IActionResult> Pin(int id, [FromBody] bool pinned)
    {
        await _db.UpdateFastSessionPinnedAsync(id, pinned);
        return Ok(new { success = true });
    }

    [HttpGet("{id}/records")]
    public async Task<IActionResult> GetRecords(int id, [FromQuery] DateTime? from = null, [FromQuery] DateTime? to = null)
    {
        var result = await _db.GetFastRecordsAsync(id, from, to);
        return Ok(new
        {
            result.SessionId, result.From, result.To,
            tagNames = result.TagNames,
            items = result.Items.Select(r => new
            {
                r.SessionId, r.RecordedAt, r.TagName, r.Value
            }),
            result.TotalCount
        });
    }

    [HttpGet("{id}/csv")]
    public async Task<IActionResult> ExportCsv(int id, [FromQuery] DateTime? from = null, [FromQuery] DateTime? to = null)
    {
        var stream = new MemoryStream();
        await _db.ExportFastRecordsToCsvAsync(id, stream, from, to);
        stream.Position = 0;
        return File(stream, "text/csv", $"fast_{id}.csv");
    }
}
