using HRD.AppLogger;
using HRD.WebApi.DAL;
using HRD.WebApi.Repositories;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace HRD.WebApi.Controllers
{
    [Route("api/[controller]")]
    [Produces("application/json")]
    [ApiController] //Automatically responding with a 400 when validation errors occur
    public abstract class BaseController<TEntity> : Microsoft.AspNetCore.Mvc.Controller where TEntity : BaseEntity, new()
    {
        private readonly IBaseRepository<TEntity> _entityRepository;
        private readonly ILoggerManager _logger;

        public BaseController(IBaseRepository<TEntity> baseRepository) : base()
        {
            _entityRepository = baseRepository;
            _logger = new LoggerManager();
        }

        protected IBaseRepository<TEntity> EntityRepository => _entityRepository;

        [HttpPost()]
        public virtual async Task<ActionResult<TEntity>> CreateAsync([FromBody] TEntity entity)
        {
            try
            {
                if (!await EntityRepository.AddAsync(entity))
                {
                    WriteLogError($"Cann't add a {typeof(TEntity).Name}");
                    return StatusCode(StatusCodes.Status400BadRequest, $"Can't create a {typeof(TEntity).Name}");
                }
                return new OkObjectResult(entity);
            }
            catch (Exception ex)
            {
                WriteLogException(ex, typeof(TEntity).Name);
                WriteLogError($"Cann't create : {ex.Message}");
                return StatusCode(StatusCodes.Status400BadRequest, $"Can't create a {typeof(TEntity).Name}");
            }
        }

        [HttpPost("List")]
        public virtual async Task<ActionResult> CreateListAsync([FromBody] List<TEntity> entities)
        {
            try
            {
                if (!await EntityRepository.AddListAsync(entities))
                {
                    WriteLogError($"Can't create a list of {typeof(TEntity).Name}");
                    return StatusCode(StatusCodes.Status400BadRequest, $"Can't create a list of {typeof(TEntity).Name}");
                }
                return new OkObjectResult(entities);
            }
            catch (Exception ex)
            {
                WriteLogException(ex, typeof(TEntity).Name);
                return StatusCode(StatusCodes.Status400BadRequest, $"Can't create a list of {typeof(TEntity).Name}");
            }
        }

        [HttpDelete("{id}")]
        public virtual async Task<ActionResult<bool>> DeleteAsync(int id)
        {
            try
            {
                if (!await EntityRepository.DeleteByIdAsync(id))
                {
                    WriteLogError($"Cann't delete the entity {typeof(TEntity).Name} Id: {id}");
                    return StatusCode(StatusCodes.Status404NotFound, $"Cann't delete {typeof(TEntity).Name} by Id: {id}");
                }
                return StatusCode(StatusCodes.Status200OK, true);
            }
            catch (Exception ex)
            {
                WriteLogException(ex, typeof(TEntity).Name);
                return StatusCode(StatusCodes.Status404NotFound, $"Cann't delete entity by Id: {id} {ex.Message}");
            }
        }

        [HttpGet("all")]
        public virtual async Task<ActionResult> GetAllAsync()
        {
            try
            {
                List<TEntity> list = await EntityRepository.GetAllAsync();
                if (list == default)
                {
                    WriteLogError($"The List of {typeof(TEntity).Name} is null");
                    return StatusCode(StatusCodes.Status400BadRequest, $"The list {typeof(TEntity).Name} cannot be loaded");
                }
                return new OkObjectResult(list);
            }
            catch (Exception ex)
            {
                WriteLogException(ex, typeof(TEntity).Name);
                return StatusCode(StatusCodes.Status400BadRequest, $"The list {typeof(TEntity).Name} cannot be loaded");
            }
        }

        [HttpGet("{id}")]
        public virtual async Task<ActionResult<TEntity>> GetEntityAsync(int id)
        {
            try
            {
                var result = await EntityRepository.GetByIdAsync(id);

                if (result == null)
                {
                    WriteLogError($"Cann't get the entity: {typeof(TEntity).Name} Id: {id}");
                    return StatusCode(StatusCodes.Status404NotFound, $"Cann't get the entity: {typeof(TEntity).Name} Id: {id}");
                }

                return new OkObjectResult(result);
            }
            catch (Exception ex)
            {
                WriteLogException(ex, typeof(TEntity).Name);
                return StatusCode(StatusCodes.Status404NotFound, $"Cann't get the entity: {typeof(TEntity).Name} Id: {id}");
            }
        }

        [HttpPut("list")]
        public virtual async Task<ActionResult<bool>> UpdateAsync(List<TEntity> entities)
        {
            try
            {
                if (!await EntityRepository.UpdateListAsync(entities))
                {
                    WriteLogError($"Cann't update the list of {typeof(TEntity).Name}");
                    return StatusCode(StatusCodes.Status400BadRequest, $"Cann't update the list of {typeof(TEntity).Name}");
                }
                return new ObjectResult(true);
            }
            catch (Exception ex)
            {
                WriteLogException(ex, typeof(TEntity).Name);
                return StatusCode(StatusCodes.Status400BadRequest, $"Cann't update the list of {typeof(TEntity).Name}");
            }
        }

        [HttpPut("{id}")]
        public virtual async Task<ActionResult<TEntity>> UpdateAsync(TEntity entity)
        {
            try
            {
                if (!await EntityRepository.UpdateAsync(entity))
                {
                    WriteLogError($"Cann't update the a {typeof(TEntity).Name}");
                    return StatusCode(StatusCodes.Status400BadRequest, $"{nameof(entity).GetType().Name} could not be updated");
                }
                return new OkObjectResult(entity);
            }
            catch (Exception ex)
            {
                WriteLogException(ex, typeof(TEntity).Name);
                return StatusCode(StatusCodes.Status400BadRequest, $"{nameof(entity).GetType().Name} could not be updated");
            }
        }

        [NonAction]
        public void WriteLogDebug(string message, String entityMessage = null)
        {
            WriteLogDebug(message, entityMessage);
        }

        [NonAction]
        public void WriteLogError(string message, String entityMessage = null)
        {
            _logger.LogError(message, entityMessage);
        }

        [NonAction]
        public void WriteLogException(Exception exception, String entityMessage = null)
        {
            _logger.LogException(exception, entityMessage);
        }

        [NonAction]
        public void WriteLogInfo(string message)
        {
            _logger.LogInfo(message);
        }

        [NonAction]
        public void WriteLogWarn(string message, String entityMessage = null)
        {
            _logger.LogWarn(message, entityMessage);
        }
    }
}