﻿using System;
using System.Security;
using Communist.Services;
using Communist.Testing;
using Xunit;

namespace Communist.Tests
{
    public class ServiceTests
    {
        [Fact]
        public void SecureServiceBase_CanSetCreated()
        {
            var service = new TestSecureService(new TestCurrentUser("ece6a619-6d51-4d2b-9064-4e0bf3836661"));
            var auditable = new TestAuditable();

            service.TestSetCreated(auditable);

            Assert.InRange(auditable.Created, DateTime.UtcNow.AddSeconds(-1), DateTime.UtcNow);
        }

        [Fact]
        public void SecureServiceBase_CanSetModified()
        {
            var service = new TestSecureService(new TestCurrentUser("ece6a619-6d51-4d2b-9064-4e0bf3836661"));
            var auditable = new TestAuditable();

            service.TestSetModified(auditable);

            Assert.InRange(auditable.Modified, DateTime.UtcNow.AddSeconds(-1), DateTime.UtcNow);
        }

        [Fact]
        public void SecureServiceBase_SetCreated_AlsoSetsModified()
        {
            var service = new TestSecureService(new TestCurrentUser("ece6a619-6d51-4d2b-9064-4e0bf3836661"));
            var auditable = new TestAuditable();

            service.TestSetCreated(auditable);

            Assert.InRange(auditable.Created, DateTime.UtcNow.AddSeconds(-1), DateTime.UtcNow);
            Assert.InRange(auditable.Modified, DateTime.UtcNow.AddSeconds(-1), DateTime.UtcNow);
        }

        [Fact]
		public void SecureServiceBase_SetCreated_SetsCreatedById()
		{
			var id = "3e8c1364-1dbe-405e-99d1-7d368f9b3649";
			var service = new TestSecureService(new TestCurrentUser(id));
			var auditable = new TestAuditable();

			service.TestSetCreated(auditable);

			Assert.Equal(id, auditable.CreatedBy);
		}

		[Fact]
		public void SecureServiceBase_SetModified_SetsModifiedById()
		{
			var id = "3ee04327-c064-4076-9927-a57047a33127";
			var service = new TestSecureService(new TestCurrentUser(id));
			var auditable = new TestAuditable();

			service.TestSetModified(auditable);

			Assert.Equal(id, auditable.ModifiedBy);
		}

		[Fact]
		public void SecureServiceBase_SetCreated_AlsoSetsModifiedById()
		{
			var id = "dd13e3fe-1d38-4928-a82a-8d86abd46a0e";
			var service = new TestSecureService(new TestCurrentUser(id));
			var auditable = new TestAuditable();

			service.TestSetCreated(auditable);

			Assert.Equal(id, auditable.ModifiedBy);
		}

		[Fact]
		public void SecureServiceBase_EnsurePermission_SecurityException_WhenPermissionNotFound()
		{
			var service = new TestSecureService(new TestCurrentUser("ece6a619-6d51-4d2b-9064-4e0bf3836661"));

			Assert.Throws<SecurityException>(() => { service.TestEnsurePermission("test"); });
		}

		[Fact]
		public void SecureServiceBase_EnsurePermission_Ok_WhenPermissionFound()
		{
			var service = new TestSecureService(new TestCurrentUser("62cc1594-3c6e-4f7c-babc-014b1b6cc4d3", permissions: new[] { "test" }));

			service.TestEnsurePermission("test");
		}

		[Fact]
		public void SecureServiceBase_EnsureRole_SecurityException_WhenRoleNotFound()
		{
			var service = new TestSecureService(new TestCurrentUser("f4a8b9a3-37da-4c0f-b2b9-735d7051c8e8"));

			Assert.Throws<SecurityException>(() => { service.TestEnsureRole("test"); });
		}

		[Fact]
		public void SecureServiceBase_EnsureRole_Ok_WhenRoleFound()
		{
			var service = new TestSecureService(new TestCurrentUser("cf01346e-8622-4bf2-a34f-8fec45179f82", roles: new[] { "test" }));

			service.TestEnsureRole("test");
		}

		[Fact]
		public void ServiceResponse_Succeeded_True()
		{
			var response = new ServiceResponse();

			Assert.True(response.Succeeded);
			Assert.Null(response.Exception);
		}

		[Fact]
		public void ServiceResponse_Failed_Succeeded_False()
		{
            var response = new ServiceResponse();
            response.Failed(new Exception());
			
			Assert.False(response.Succeeded);
			Assert.NotNull(response.Exception);
		}

        [Fact]
        public void ServiceResponse_CanStoreGenericData()
        {
            var response = new ServiceResponse<string>();
            response.Success("Test");

            Assert.True(response.Succeeded);
            Assert.Equal("Test", response.Data);
        }

        [Fact]
        public void ServiceResponse_EnsureSuccess_ThrowsExceptionWhenFailed()
        {
            var response = new ServiceResponse();
            response.Failed(new Exception());

            Assert.Throws<Exception>(() => response.EnsureSuccess());
        }

        [Fact]
        public void ServiceResponse_EnsureSuccess_DoesNotThrowExceptionWhenSuccess()
        {
            var response = new ServiceResponse();

            response.EnsureSuccess();
        }
    }
}
