using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using CounterDrone.Core.Models;
using CounterDrone.Core.Reporting;
using SQLite;
using CounterDrone.Core.Simulation;

namespace CounterDrone.Core.Services
{
    public class ReportService : IReportService
    {
        private readonly SQLiteConnection _db;
        private readonly ReportGenerator _generator = new();
        private readonly IPathProvider _paths;
        private readonly MarkdownRenderer _mdRenderer = new();
        private StandardPdfTemplate? _pdfTemplate;

        private const string FontFamily = "SimHei";
        private static readonly JsonSerializerOptions JsonOpts = new()
        {
            Converters = { new ReportBlockConverter() },
        };

        public ReportService(SQLiteConnection db, IPathProvider paths)
        {
            _db = db;
            _paths = paths;
        }

        public SimulationReport Generate(string scenarioId, ScenarioConfig config,
            List<SimEvent> events, string finalDroneStatus, float duration)
        {
            var droneSpecs = _db.Table<DroneSpec>().ToDictionary(d => d.Id);
            var fireUnitSpecs = _db.Table<LaunchPlatformSpec>().ToDictionary(f => f.Id);
            var sensorSpecs = _db.Table<SensorSpec>().ToDictionary(s => s.Id);

            var destroyed = events.Count(e => e.Type == SimEventType.DroneDestroyed);
            var reached = events.Count(e => e.Type == SimEventType.DroneReachedTarget);
            var intruded = events.Count(e => e.Type == SimEventType.ZoneIntruded);
            var total = config.Drones.Sum(t => t.Quantity);
            var result = _generator.DetermineInterceptResult(destroyed, reached + intruded, total);

            var reportData = _generator.Generate(config, events, Simulation.DroneStatus.Flying, duration,
                droneSpecs, fireUnitSpecs, sensorSpecs);

            var report = new SimulationReport
            {
                ScenarioId = scenarioId,
                ScenarioName = config.Info.Name,
                ScenarioNumber = config.Info.ScenarioNumber,
                CompletedAt = DateTime.UtcNow.ToString("o"),
                DroneCount = total,
                UnitCount = config.Units.Count,
                InterceptResult = (int)result,
                Content = _mdRenderer.Render(reportData),
                ReportDataJson = JsonSerializer.Serialize(reportData, JsonOpts),
            };

            _db.Insert(report);

            // 仿真后自动导出 Markdown 到报告目录
            var reportsDir = Path.Combine(_paths.GetDataRoot(), "reports");
            ExportToFile(report.Id, reportsDir, "md");

            return report;
        }

        public SimulationReport GetReport(string id)
        {
            return _db.Find<SimulationReport>(id);
        }

        public void DeleteReport(string id)
        {
            _db.Delete<SimulationReport>(id);
        }

        public PagedResult<SimulationReport> SearchReports(string keyword, string? dateFrom, string? dateTo, int page, int pageSize)
        {
            if (page < 1) page = 1;
            if (pageSize < 1) pageSize = 10;
            var offset = (page - 1) * pageSize;

            var query = _db.Table<SimulationReport>().AsQueryable();
            if (!string.IsNullOrWhiteSpace(keyword))
                query = query.Where(r => r.ScenarioName.Contains(keyword) || r.ScenarioNumber.Contains(keyword));
            if (!string.IsNullOrWhiteSpace(dateFrom))
                query = query.Where(r => r.CompletedAt.CompareTo(dateFrom) >= 0);
            if (!string.IsNullOrWhiteSpace(dateTo))
                query = query.Where(r => r.CompletedAt.CompareTo(dateTo) <= 0);

            var total = query.Count();
            var items = query.OrderByDescending(r => r.CompletedAt).Skip(offset).Take(pageSize).ToList();

            return new PagedResult<SimulationReport>
            {
                Items = items,
                TotalCount = total,
                Page = page,
                PageSize = pageSize,
            };
        }

        public byte[] ExportReport(string id, string format)
        {
            var report = _db.Find<SimulationReport>(id);
            if (report == null) throw new ArgumentException($"报告 {id} 不存在");

            if (format == "md")
                return Encoding.UTF8.GetBytes(report.Content);

            if (format == "pdf")
            {
                if (string.IsNullOrEmpty(report.ReportDataJson))
                    throw new InvalidOperationException($"报告 {id} 缺少结构化数据，无法导出 PDF");

                var data = JsonSerializer.Deserialize<ReportData>(report.ReportDataJson, JsonOpts)
                    ?? throw new InvalidOperationException("报告数据反序列化失败");
                _pdfTemplate ??= new StandardPdfTemplate(_paths.GetFontPath(), FontFamily);
                return _pdfTemplate.Render(data);
            }

            throw new ArgumentException($"不支持的导出格式: {format}（仅支持 pdf / md）");
        }

        public string ExportToFile(string reportId, string outputDir, string format)
        {
            var report = _db.Find<SimulationReport>(reportId);
            if (report == null) throw new ArgumentException($"报告 {reportId} 不存在");

            Directory.CreateDirectory(outputDir);
            var safeTime = DateTime.UtcNow.ToString("yyyyMMdd_HHmmss");
            var ext = format == "pdf" ? "pdf" : "md";
            var fileName = $"{report.ScenarioName}_{safeTime}.{ext}";
            var filePath = Path.Combine(outputDir, fileName);
            File.WriteAllBytes(filePath, ExportReport(reportId, format));
            return filePath;
        }
    }
}
