using System;
using System.Collections.Generic;
using System.IO;
using CounterDrone.Core.Models;
using SQLite;

namespace CounterDrone.Core.Simulation
{
    /// <summary>帧数据存储 — 内存缓存，仿真结束时批量写入 SQLite</summary>
    public class FrameDataStore
    {
        private readonly IPathProvider _paths;
        private readonly List<FrameRecord> _buffer = new();
        private string _taskId = string.Empty;
        public int RetentionDays { get; set; } = 180;
        public int BufferedFrameCount { get; private set; }

        public FrameDataStore(IPathProvider paths)
        {
            _paths = paths;
        }

        /// <summary>开始录制。清空缓冲区，准备接收帧数据。</summary>
        public void BeginRecording(string taskId)
        {
            _taskId = taskId;
            _buffer.Clear();
            BufferedFrameCount = 0;
        }

        /// <summary>记录一帧所有实体的快照（仅内存，零字符串分配）</summary>
        public void RecordFrame(int frameIdx, float timestamp, List<EntitySnapshot> snapshots)
        {
            for (int i = 0; i < snapshots.Count; i++)
            {
                var s = snapshots[i];
                _buffer.Add(new FrameRecord
                {
                    FrameIndex = frameIdx, Timestamp = timestamp,
                    Snapshot = new EntitySnapshot
                    {
                        EntityId = s.EntityId, EntityType = s.EntityType,
                        PosX = s.PosX, PosY = s.PosY, PosZ = s.PosZ,
                        DamageStage = s.DamageStage, Hp = s.Hp,
                        PlatformStateStr = s.PlatformStateStr,
                        CloudRadius = s.CloudRadius, CloudOpacity = s.CloudOpacity,
                        CloudPhase = s.CloudPhase, CloudElapsed = s.CloudElapsed,
                    }
                });
            }
            BufferedFrameCount = frameIdx + 1;
        }

        /// <summary>将缓冲区序列化为 JSON 并批量写入 SQLite</summary>
        public void Flush()
        {
            if (_buffer.Count == 0) return;
            var records = new List<SimFrameRecord>(_buffer.Count);
            for (int i = 0; i < _buffer.Count; i++)
            {
                var fr = _buffer[i];
                var s = fr.Snapshot;
                records.Add(new SimFrameRecord
                {
                    TaskId = _taskId, FrameIndex = fr.FrameIndex, Timestamp = fr.Timestamp,
                    EntityId = s.EntityId, EntityType = (int)s.EntityType,
                    PosX = s.PosX, PosY = s.PosY, PosZ = s.PosZ,
                    StateData = s.EntityType switch
                    {
                        Models.EntityType.Drone => $"{{\"damageStage\":{s.DamageStage},\"hp\":{s.Hp:F2}}}",
                        Models.EntityType.Platform => $"{{\"state\":\"{s.PlatformStateStr}\"}}",
                        Models.EntityType.Cloud => $"{{\"radius\":{s.CloudRadius:F1},\"opacity\":{s.CloudOpacity:F2},\"phase\":{s.CloudPhase},\"elapsed\":{s.CloudElapsed:F1}}}",
                        _ => "{}",
                    },
                });
            }
            _buffer.Clear();

            var dbPath = Path.Combine(_paths.GetFramesDir(), $"{_taskId}.db");
            Directory.CreateDirectory(_paths.GetFramesDir());
            using var db = new SQLiteConnection(dbPath);
            db.CreateTable<SimFrameRecord>();
            db.CreateIndex("SimFrameRecord", new[] { "TaskId", "FrameIndex" });
            db.InsertAll(records);
        }
        
        public void Discard() { _buffer.Clear(); BufferedFrameCount = 0; }

        public List<SimFrameRecord> ReadFrames(string taskId, int fromFrame, int toFrame)
        {
            var dbPath = Path.Combine(_paths.GetFramesDir(), $"{taskId}.db");
            if (!File.Exists(dbPath)) return new List<SimFrameRecord>();
            using var db = new SQLiteConnection(dbPath);
            return db.Table<SimFrameRecord>()
                     .Where(f => f.TaskId == taskId && f.FrameIndex >= fromFrame && f.FrameIndex <= toFrame)
                     .OrderBy(f => f.FrameIndex)
                     .ToList();
        }

        public void DeleteFrameDb(string taskId)
        {
            var dbPath = Path.Combine(_paths.GetFramesDir(), $"{taskId}.db");
            if (File.Exists(dbPath)) File.Delete(dbPath);
        }

        /// <summary>清理过期的帧数据库文件</summary>
        public int CleanupExpired()
        {
            var dir = _paths.GetFramesDir();
            if (!Directory.Exists(dir)) return 0;
            var cutoff = DateTime.Now.AddDays(-RetentionDays);
            var deleted = 0;
            foreach (var file in Directory.GetFiles(dir, "*.db"))
            {
                if (File.GetCreationTime(file) < cutoff)
                {
                    File.Delete(file);
                    deleted++;
                }
            }
            return deleted;
        }
    }

    internal struct FrameRecord
    {
        public int FrameIndex;
        public float Timestamp;
        public EntitySnapshot Snapshot;
    }
}
