using System;
using System.IO;
using FluentAssertions;
using MarcusLaw.OutlookAddin.Core.Security;
using Xunit;

namespace MarcusLaw.OutlookAddin.Tests.Security
{
    public class DpapiCredentialStoreTests : IDisposable
    {
        private readonly string _tempDir;

        public DpapiCredentialStoreTests()
        {
            _tempDir = Path.Combine(Path.GetTempPath(), "OutlookAddinTests-" + Guid.NewGuid().ToString("N"));
            Directory.CreateDirectory(_tempDir);
        }

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

        private DpapiCredentialStore NewStore() =>
            new DpapiCredentialStore(Path.Combine(_tempDir, "creds.dat"));

        [Fact]
        public void Save_ThenLoad_RoundTripsCredentials()
        {
            var store = NewStore();

            store.Save("chaim@marcus-law.co.il", "abc123-secret");
            var loaded = store.Load();

            loaded.Should().NotBeNull();
            loaded!.Username.Should().Be("chaim@marcus-law.co.il");
            loaded.ApiKey.Should().Be("abc123-secret");
        }

        [Fact]
        public void Save_HebrewUsername_RoundTripsCorrectly()
        {
            var store = NewStore();

            store.Save("חיים@marcus-law.co.il", "מפתח-סודי-עברי");
            var loaded = store.Load();

            loaded!.Username.Should().Be("חיים@marcus-law.co.il");
            loaded.ApiKey.Should().Be("מפתח-סודי-עברי");
        }

        [Fact]
        public void Load_ReturnsNull_WhenFileMissing()
        {
            var store = NewStore();

            var loaded = store.Load();

            loaded.Should().BeNull();
        }

        [Fact]
        public void Save_CreatesParentDirectory_WhenMissing()
        {
            var nested = Path.Combine(_tempDir, "nested", "deep", "creds.dat");
            var store = new DpapiCredentialStore(nested);

            store.Save("u", "k");

            File.Exists(nested).Should().BeTrue();
        }

        [Fact]
        public void Save_WritesEncryptedBytes_NotPlaintext()
        {
            var store = NewStore();
            store.Save("u", "supersecretkey-distinctive-marker");

            var bytes = File.ReadAllBytes(store.FilePath);
            var asText = System.Text.Encoding.UTF8.GetString(bytes);

            asText.Should().NotContain("supersecretkey-distinctive-marker");
        }

        [Fact]
        public void Delete_RemovesFile()
        {
            var store = NewStore();
            store.Save("u", "k");
            File.Exists(store.FilePath).Should().BeTrue();

            store.Delete();

            File.Exists(store.FilePath).Should().BeFalse();
        }

        [Fact]
        public void Save_RejectsBlankApiKey()
        {
            var store = NewStore();
            // Empty username is OK (some EspoCRM API-User installs need only the key);
            // empty apiKey is not.
            Assert.Throws<ArgumentException>(() => store.Save("u", ""));
        }

        [Fact]
        public void Save_AcceptsEmptyUsername()
        {
            var store = NewStore();
            store.Save(null, "key-only");
            var loaded = store.Load();
            loaded.Should().NotBeNull();
            loaded!.Username.Should().BeEmpty();
            loaded.ApiKey.Should().Be("key-only");
        }
    }
}
