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

namespace CounterDrone.Core.Tests
{
    public class ReportServiceTests : IDisposable
    {
        private readonly string _testDir;
        private readonly IReportService _service;
        private readonly SQLiteConnection _db;

        public ReportServiceTests()
        {
            _testDir = Path.Combine(Path.GetTempPath(), $"cd_rep_{Guid.NewGuid():N}");
            var paths = new TestPathProvider(_testDir);
            var dbm = new DatabaseManager(paths);
            _db = dbm.OpenMainDb();
            _service = new ReportService(_db, paths);
        }

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

        private ScenarioConfig CreateTestConfig()
        {
            return new ScenarioConfig
            {
                Info = new Scenario { Name = "Test", ScenarioNumber = "SIM-001" },
                Drones = new List<ScenarioDrone> { TestData.CreateScenarioDrone("w1", 1) },
                Units = new List<ScenarioUnit>(),
                Cloud = new CloudDispersal(),
            };
        }

        [Fact]
        public void Generate_And_Get_ReturnsReport()
        {
            var report = _service.Generate("scenario1", CreateTestConfig(), new List<SimEvent>(), "Destroyed", 45f);

            Assert.NotNull(report);
            Assert.NotEmpty(report.Id);
            Assert.Equal("Test", report.ScenarioName);
            Assert.Contains("仿真评估报告", report.Content);
            Assert.NotNull(report.ReportDataJson);

            var fetched = _service.GetReport(report.Id);
            Assert.NotNull(fetched);
        }

        [Fact]
        public void Delete_RemovesReport()
        {
            var report = _service.Generate("scenario1", CreateTestConfig(), new List<SimEvent>(), "Destroyed", 10f);
            _service.DeleteReport(report.Id);
            Assert.Null(_service.GetReport(report.Id));
        }

        [Fact]
        public void SearchReports_Keyword()
        {
            var cfg = CreateTestConfig();
            cfg.Info.Name = "城市防御";
            _service.Generate("t1", cfg, new List<SimEvent>(), "Destroyed", 10f);
            cfg.Info.Name = "平原拦截";
            cfg.Info.ScenarioNumber = "SIM-B";
            _service.Generate("t2", cfg, new List<SimEvent>(), "Destroyed", 20f);

            var result = _service.SearchReports("城市", null, null, 1, 10);
            Assert.Equal(1, result.TotalCount);
        }

        [Fact]
        public void ExportReport_Md_ReturnsMarkdownBytes()
        {
            var report = _service.Generate("scenario1", CreateTestConfig(), new List<SimEvent>(), "Destroyed", 45f);
            var md = _service.ExportReport(report.Id, "md");
            var text = Encoding.UTF8.GetString(md);
            Assert.Contains("仿真评估报告", text);
        }

        [Fact]
        public void ExportReport_Pdf_ReturnsValidPdf()
        {
            var report = _service.Generate("scenario1", CreateTestConfig(), new List<SimEvent>(), "Destroyed", 45f);
            var pdf = _service.ExportReport(report.Id, "pdf");
            Assert.NotEmpty(pdf);
            // PDF 文件以 "%PDF" 开头
            Assert.Equal(0x25, pdf[0]); // %
            Assert.Equal(0x50, pdf[1]); // P
            Assert.Equal(0x44, pdf[2]); // D
            Assert.Equal(0x46, pdf[3]); // F
        }

        [Fact]
        public void ExportReport_Pdf_MissingReportData_Throws()
        {
            var report = new SimulationReport
            {
                ScenarioId = "s1",
                ScenarioName = "Old",
                Content = "# Old Report",
                ReportDataJson = null,
            };
            _db.Insert(report);

            Assert.Throws<InvalidOperationException>(() => _service.ExportReport(report.Id, "pdf"));
        }

        [Fact]
        public void ExportReport_UnsupportedFormat_Throws()
        {
            var report = _service.Generate("scenario1", CreateTestConfig(), new List<SimEvent>(), "Destroyed", 45f);
            Assert.Throws<ArgumentException>(() => _service.ExportReport(report.Id, "docx"));
        }

        [Fact]
        public void ExportToFile_Pdf_CreatesPdfFile()
        {
            var report = _service.Generate("scenario1", CreateTestConfig(), new List<SimEvent>(), "Destroyed", 45f);
            var path = _service.ExportToFile(report.Id, _testDir, "pdf");
            Assert.True(File.Exists(path));
            Assert.EndsWith(".pdf", path);
        }

        [Fact]
        public void ExportToFile_Md_CreatesMdFile()
        {
            var report = _service.Generate("scenario1", CreateTestConfig(), new List<SimEvent>(), "Destroyed", 45f);
            var path = _service.ExportToFile(report.Id, _testDir, "md");
            Assert.True(File.Exists(path));
            Assert.EndsWith(".md", path);
            var content = File.ReadAllText(path);
            Assert.Contains("仿真评估报告", content);
        }

        [Fact]
        public void Generate_AutoExportsMdToReportsDir()
        {
            var report = _service.Generate("scenario1", CreateTestConfig(), new List<SimEvent>(), "Destroyed", 45f);
            var reportsDir = Path.Combine(_testDir, "reports");
            Assert.True(Directory.Exists(reportsDir));
            var mdFiles = Directory.GetFiles(reportsDir, "*.md");
            Assert.True(mdFiles.Length > 0, "仿真后应自动生成 MD 文件到 reports 目录");
        }
    }
}
