using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using FluentAssertions;
using MarcusLaw.OutlookAddin.Core.Models;
using MarcusLaw.OutlookAddin.Core.Services;
using Serilog;
using Xunit;

namespace MarcusLaw.OutlookAddin.Tests.Services
{
    public class DiskRetryQueueTests : IDisposable
    {
        private readonly string _tempDir;
        private readonly ILogger _logger;

        public DiskRetryQueueTests()
        {
            _tempDir = Path.Combine(Path.GetTempPath(), "OutlookAddinTests", Guid.NewGuid().ToString("N"));
            _logger = new LoggerConfiguration().CreateLogger();
        }

        public void Dispose()
        {
            if (Directory.Exists(_tempDir))
            {
                Directory.Delete(_tempDir, recursive: true);
            }
        }

        private DiskRetryQueue MakeQueue() => new DiskRetryQueue(_tempDir, _logger);

        [Fact]
        public async Task Enqueue_CreatesDirectoryAndAssignsId()
        {
            var queue = MakeQueue();
            var id = await queue.EnqueueAsync(new RetryQueueItem
            {
                TargetName = "Smith Family",
                Request = new FileEmailRequest { ParentType = "Case", ParentId = "case-1", Subject = "x" }
            });

            id.Should().NotBeNullOrEmpty();
            Directory.Exists(_tempDir).Should().BeTrue();
            File.Exists(Path.Combine(_tempDir, id + ".json")).Should().BeTrue();
        }

        [Fact]
        public async Task Enqueue_StoresHebrewPayload_RoundTripsViaListAll()
        {
            var queue = MakeQueue();
            var hebrewSubject = "תיק משפחת כהן — דיון יום ראשון";
            var hebrewTarget = "תיק כהן נ' לוי";
            await queue.EnqueueAsync(new RetryQueueItem
            {
                TargetName = hebrewTarget,
                LastError = "שגיאת רשת",
                Request = new FileEmailRequest
                {
                    ParentType = "Case",
                    ParentId = "case-1",
                    Subject = hebrewSubject
                }
            });

            var all = await queue.ListAllAsync();

            all.Should().HaveCount(1);
            all[0].TargetName.Should().Be(hebrewTarget);
            all[0].LastError.Should().Be("שגיאת רשת");
            all[0].Request.Subject.Should().Be(hebrewSubject);
        }

        [Fact]
        public async Task ListAll_ReturnsEmptyWhenDirectoryMissing()
        {
            var queue = MakeQueue();
            var all = await queue.ListAllAsync();
            all.Should().BeEmpty();
        }

        [Fact]
        public async Task ListAll_SkipsCorruptFiles()
        {
            Directory.CreateDirectory(_tempDir);
            File.WriteAllText(Path.Combine(_tempDir, "corrupt.json"), "{not valid json");

            var queue = MakeQueue();
            await queue.EnqueueAsync(new RetryQueueItem
            {
                Request = new FileEmailRequest { ParentType = "Case", ParentId = "case-1" }
            });

            var all = await queue.ListAllAsync();
            all.Should().HaveCount(1);
        }

        [Fact]
        public async Task Remove_DeletesFile()
        {
            var queue = MakeQueue();
            var id = await queue.EnqueueAsync(new RetryQueueItem
            {
                Request = new FileEmailRequest { ParentType = "Case", ParentId = "case-1" }
            });

            await queue.RemoveAsync(id);

            File.Exists(Path.Combine(_tempDir, id + ".json")).Should().BeFalse();
            (await queue.ListAllAsync()).Should().BeEmpty();
        }

        [Fact]
        public async Task Remove_IsIdempotent()
        {
            var queue = MakeQueue();
            await queue.RemoveAsync("does-not-exist");
            (await queue.ListAllAsync()).Should().BeEmpty();
        }

        [Fact]
        public async Task Enqueue_OverwritesExistingIdAtomically()
        {
            var queue = MakeQueue();
            var item = new RetryQueueItem
            {
                Id = "fixed-id",
                Request = new FileEmailRequest { ParentType = "Case", ParentId = "case-1", Subject = "v1" }
            };
            await queue.EnqueueAsync(item);

            item.Request.Subject = "v2";
            item.AttemptCount = 1;
            await queue.EnqueueAsync(item);

            var all = await queue.ListAllAsync();
            all.Should().HaveCount(1);
            all[0].Request.Subject.Should().Be("v2");
            all[0].AttemptCount.Should().Be(1);

            Directory.EnumerateFiles(_tempDir, "*.tmp").Should().BeEmpty();
        }
    }
}
