using AsbCloudApp.Data;
using AsbCloudApp.Services;
using AsbCloudWebApi.Controllers;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Moq;
using System;
using System.Collections.Generic;
using System.Security.Claims;
using Xunit;

namespace AsbCloudWebApi.Tests.ControllersTests
{
    public class AnalyticsControllerTests
    {
        private readonly Mock<ITelemetryAnalyticsService> analyticsService;
        private readonly Mock<IWellService> wellService;
        private readonly TelemetryAnalyticsController controller;
        private readonly List<WellDepthToDayDto> depthToDayDtos;

        // fills class fields with data. Each test inside can change this data themselves for their needs
        public AnalyticsControllerTests()
        {
            analyticsService = new Mock<ITelemetryAnalyticsService>();
            wellService = new Mock<IWellService>();

            depthToDayDtos = new List<WellDepthToDayDto>()
            {
                new WellDepthToDayDto { WellDepth = 1000.0, BitDepth = 1000.0, Date = DateTime.Now },
                new WellDepthToDayDto { WellDepth = 2000.0, BitDepth = 2000.0, Date = DateTime.Now },
                new WellDepthToDayDto { WellDepth = 3000.0, BitDepth = 3000.0, Date = DateTime.Now }
            };

            analyticsService.Setup(s => s.GetWellDepthToDay(It.IsAny<int>()))
                            .Returns(depthToDayDtos);

            wellService.Setup(s => s.IsCompanyInvolvedInWell(It.IsAny<int>(), It.IsAny<int>()))
                            .Returns(true);

            controller = new TelemetryAnalyticsController(analyticsService.Object,
                wellService.Object);

            var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[]
                        {
                            new Claim("idCompany", "1"),
                        }, "mock"));

            controller.ControllerContext = new ControllerContext()
            {
                HttpContext = new DefaultHttpContext() { User = user }
            };
        }

        [Fact]
        public void It_should_return_depth_to_day_analytics()
        {
            var result = controller.GetWellDepthToDay(1);
            var okResult = result as OkObjectResult;

            Assert.NotNull(okResult);
        }

        [Fact]
        public void It_should_return_correct_count_depth_to_day_analytics()
        {
            var result = controller.GetWellDepthToDay(1);
            var okResult = result as OkObjectResult;
            var resultCount = ((List<WellDepthToDayDto>)okResult.Value).Count;

            Assert.Equal(3, resultCount);
        }

        [Fact]
        public void It_should_return_403_if_no_idCompany()
        {
            var emptyUserController = new TelemetryAnalyticsController(analyticsService.Object,
                wellService.Object);

            var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] { }, "mock"));

            emptyUserController.ControllerContext = new ControllerContext()
            {
                HttpContext = new DefaultHttpContext() { User = user }
            };

            var result = emptyUserController.GetWellDepthToDay(1);
            var forbidResult = result as ForbidResult;

            Assert.NotNull(forbidResult);
        }

        [Fact]
        public void It_should_return_403_if_user_doesnt_own_well()
        {
            var wellServiceReturnsFalse = new Mock<IWellService>();

            wellServiceReturnsFalse.Setup(s => s.IsCompanyInvolvedInWell(It.IsAny<int>(), It.IsAny<int>()))
                            .Returns(false);

            var newControllerInstance = new TelemetryAnalyticsController(analyticsService.Object,
                        wellServiceReturnsFalse.Object);

            var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[]
            {
                new Claim("idCompany", "1"),
            }, "mock"));

            newControllerInstance.ControllerContext = new ControllerContext()
            {
                HttpContext = new DefaultHttpContext() { User = user }
            };

            var result = newControllerInstance.GetWellDepthToDay(1);
            var forbidResult = result as ForbidResult;

            Assert.NotNull(forbidResult);
        }

        [Fact]
        public void It_should_return_204_if_dtos_is_empty()
        {
            var emptyAnalyticsService = new Mock<ITelemetryAnalyticsService>();

            emptyAnalyticsService.Setup(s => s.GetWellDepthToDay(It.IsAny<int>()))
                            .Returns(new List<WellDepthToDayDto>());

            var newControllerInstance = new TelemetryAnalyticsController(emptyAnalyticsService.Object,
                    wellService.Object);

            var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[]
            {
                new Claim("idCompany", "1"),
            }, "mock"));

            newControllerInstance.ControllerContext = new ControllerContext()
            {
                HttpContext = new DefaultHttpContext() { User = user }
            };

            var result = newControllerInstance.GetWellDepthToDay(1);
            var notFoundResult = result as NoContentResult;

            Assert.NotNull(notFoundResult);
        }

        [Fact]
        public void It_should_return_204_if_dtos_is_null()
        {
            var emptyAnalyticsService = new Mock<ITelemetryAnalyticsService>();

            emptyAnalyticsService.Setup(s => s.GetWellDepthToDay(It.IsAny<int>()))
                            .Returns(value: null);

            var newControllerInstance = new TelemetryAnalyticsController(emptyAnalyticsService.Object,
                    wellService.Object);

            var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[]
            {
                new Claim("idCompany", "1"),
            }, "mock"));

            newControllerInstance.ControllerContext = new ControllerContext()
            {
                HttpContext = new DefaultHttpContext() { User = user }
            };

            var result = newControllerInstance.GetWellDepthToDay(1);
            var notFoundResult = result as NoContentResult;

            Assert.NotNull(notFoundResult);
        }
    }
}