using System;
using System.Collections.Generic;
using System.IO;
using CounterDrone.Core;
using CounterDrone.Core.Models;
using CounterDrone.Core.Simulation;
using Xunit;

namespace CounterDrone.Core.Tests
{
    public class FrameDataStoreTests : IDisposable
    {
        private readonly string _testDir;
        private readonly FrameDataStore _store;

        public FrameDataStoreTests()
        {
            _testDir = Path.Combine(Path.GetTempPath(), $"cd_frames_{Guid.NewGuid():N}");
            var paths = new TestPathProvider(_testDir);
            _store = new FrameDataStore(paths);
        }

        public void Dispose()
        {
            if (Directory.Exists(_testDir)) Directory.Delete(_testDir, true);
        }

        private void CreateFakeDb(string scenarioId)
        {
            _store.BeginRecording(scenarioId);
            _store.RecordFrame(0, 0f, new List<EntitySnapshot> { new EntitySnapshot { EntityId = "d1" } });
            _store.Flush();
        }

        [Fact]
        public void CleanupExpired_DeletesOldFiles()
        {
            _store.RetentionDays = 0;
            CreateFakeDb("scenario_old_1");
            CreateFakeDb("scenario_old_2");

            var deleted = _store.CleanupExpired();
            Assert.Equal(2, deleted);
            Assert.False(File.Exists(Path.Combine(_testDir, "frames", "scenario_old_1.db")));
            Assert.False(File.Exists(Path.Combine(_testDir, "frames", "scenario_old_2.db")));
        }

        [Fact]
        public void CleanupExpired_KeepsRecentFiles()
        {
            _store.RetentionDays = 365;
            CreateFakeDb("scenario_new");

            var filePath = Path.Combine(_testDir, "frames", "scenario_new.db");
            File.SetCreationTime(filePath, DateTime.Now);

            var deleted = _store.CleanupExpired();
            Assert.Equal(0, deleted);
            Assert.True(File.Exists(filePath));
        }

        [Fact]
        public void CleanupExpired_EmptyDir_ReturnsZero()
        {
            Assert.Equal(0, _store.CleanupExpired());
        }

        [Fact]
        public void RecordAndFlush_ThenReadFrames()
        {
            _store.BeginRecording("scenario_rw");
            var snapshots = new List<EntitySnapshot>
            {
                new EntitySnapshot { EntityId = "d1", EntityType = Models.EntityType.Drone, PosX = 100 },
            };
            _store.RecordFrame(0, 0f, snapshots);
            _store.RecordFrame(1, 0.05f, snapshots);
            _store.RecordFrame(2, 0.10f, snapshots);
            _store.Flush();

            var frames = _store.ReadFrames("scenario_rw", 1, 2);
            Assert.Equal(2, frames.Count);
            Assert.Equal(1, frames[0].FrameIndex);
            Assert.Equal(2, frames[1].FrameIndex);
        }

        [Fact]
        public void Flush_EmptyBuffer_DoesNothing()
        {
            _store.BeginRecording("scenario_empty");
            _store.Flush(); // no crash
            Assert.False(File.Exists(Path.Combine(_testDir, "frames", "scenario_empty.db")));
        }

        [Fact]
        public void Discard_ClearsBuffer()
        {
            _store.BeginRecording("scenario_discard");
            _store.RecordFrame(0, 0f, new List<EntitySnapshot> { new EntitySnapshot { EntityId = "d1" } });
            _store.Discard();
            Assert.Equal(0, _store.BufferedFrameCount);
        }
    }
}
