﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using FictionHub.Domain.Core.Bus;
using FictionHub.Domain.Core.Notifications;
using MediatR;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace FictionHub.Services.Api.Controllers
{
    public abstract class ApiController : ControllerBase
    {
        private DomainNotificationHandler _notifications;
        private IMediatorHandler _mediator;

        protected ApiController(INotificationHandler<DomainNotification> notifications,
            IMediatorHandler mediator)
        {
            _notifications = (DomainNotificationHandler)notifications;
            _mediator = mediator;
        }

        protected IEnumerable<DomainNotification> Notifications => _notifications.GetNotifications();

        protected bool IsValidOperation()
        {
            return !_notifications.HasNotifications();
        }

        protected new IActionResult Response(object result = null)
        {
            var settings = new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() };
            #if (DEBUG)
            settings.Formatting = Formatting.Indented;
            #endif

            if (IsValidOperation())
            {
                return Ok(new
                {
                    success = true,
                    data = JsonConvert.SerializeObject(result, settings)
                });
            }

            return BadRequest(new
            {
                success = false,
                errors = _notifications.GetNotifications().Select(n => n.Value)
            });
        }

        protected void NotifyModelStateErrors()
        {
            var errors = ModelState.Values.SelectMany(x => x.Errors);
            foreach (var error in errors)
            {
                var errorMessage = error.Exception?.Message ?? error.ErrorMessage;
                NotifyError(string.Empty, errorMessage);
            }
        }
        
        protected void NotifyError(string code, string message)
        {
            _mediator.RaiseEvent(new DomainNotification(code, message));
        }

        protected void AddIdentityErrors(IdentityResult result)
        {
            foreach (var error in result.Errors)
            {
                NotifyError(result.ToString(), error.Description);
            }
        }
    }
}