using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Logging;
using AyaNova.Models;
using AyaNova.Api.ControllerHelpers;
using AyaNova.Biz;


namespace AyaNova.Api.Controllers
{
    //DOCUMENTATING THE API
    //https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/xmldoc/recommended-tags-for-documentation-comments
    //https://github.com/domaindrivendev/Swashbuckle.AspNetCore#include-descriptions-from-xml-comments

    /// <summary>
    /// Sample controller class used during development for testing purposes
    /// </summary>
    [ApiController]
    [ApiVersion("8.0")]
    [Route("api/v{version:apiVersion}/widget")]
    [Produces("application/json")]
    [Authorize]
    public class WidgetController : ControllerBase
    {
        private readonly AyContext ct;
        private readonly ILogger<WidgetController> log;
        private readonly ApiServerState serverState;


        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="dbcontext"></param>
        /// <param name="logger"></param>
        /// <param name="apiServerState"></param>  
        public WidgetController(AyContext dbcontext, ILogger<WidgetController> logger, ApiServerState apiServerState)
        {
            ct = dbcontext;
            log = logger;
            serverState = apiServerState;
        }

        /// <summary>
        /// Create Widget
        /// </summary>
        /// <param name="newObject"></param>
        /// <param name="apiVersion">From route path</param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> PostWidget([FromBody] Widget newObject, ApiVersion apiVersion)
        {
            if (!serverState.IsOpen)
                return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
            WidgetBiz biz = WidgetBiz.GetBiz(ct, HttpContext);
            if (!Authorized.HasCreateRole(HttpContext.Items, biz.BizType))
                return StatusCode(403, new ApiNotAuthorizedResponse());
            if (!ModelState.IsValid)
                return BadRequest(new ApiErrorResponse(ModelState));
            Widget o = await biz.CreateAsync(newObject);
            if (o == null)
                return BadRequest(new ApiErrorResponse(biz.Errors));
            else
                return CreatedAtAction(nameof(WidgetController.GetWidget), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(o));
        }

        /// <summary>
        /// Duplicate Widget
        /// (Wiki and Attachments are not duplicated)
        /// </summary>
        /// <param name="id">Source object id</param>
        /// <param name="apiVersion">From route path</param>
        /// <returns>Widget</returns>
        [HttpPost("duplicate/{id}")]
        public async Task<IActionResult> DuplicateWidget([FromRoute] long id, ApiVersion apiVersion)
        {
            if (!serverState.IsOpen)
                return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
            WidgetBiz biz = WidgetBiz.GetBiz(ct, HttpContext);
            if (!Authorized.HasCreateRole(HttpContext.Items, biz.BizType))
                return StatusCode(403, new ApiNotAuthorizedResponse());
            if (!ModelState.IsValid)
                return BadRequest(new ApiErrorResponse(ModelState));
            Widget o = await biz.DuplicateAsync(id);
            if (o == null)
                return BadRequest(new ApiErrorResponse(biz.Errors));
            else
                return CreatedAtAction(nameof(WidgetController.GetWidget), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(o));
        }

        /// <summary>
        /// Get Widget
        /// </summary>
        /// <param name="id"></param>
        /// <returns>Widget</returns>
        [HttpGet("{id}")]
        public async Task<IActionResult> GetWidget([FromRoute] long id)
        {
            if (!serverState.IsOpen)
                return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
            WidgetBiz biz = WidgetBiz.GetBiz(ct, HttpContext);
            if (!Authorized.HasReadFullRole(HttpContext.Items, biz.BizType))
                return StatusCode(403, new ApiNotAuthorizedResponse());
            if (!ModelState.IsValid)
                return BadRequest(new ApiErrorResponse(ModelState));
            var o = await biz.GetAsync(id);
            if (o == null) return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND));
            return Ok(ApiOkResponse.Response(o));
        }

        /// <summary>
        /// Put (update) Widget
        /// </summary>        
        /// <param name="updatedObject"></param>
        /// <returns></returns>
        [HttpPut]
        public async Task<IActionResult> PutWidget([FromBody] Widget updatedObject)
        {
            if (!serverState.IsOpen)
                return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
            if (!ModelState.IsValid)
                return BadRequest(new ApiErrorResponse(ModelState));
            WidgetBiz biz = WidgetBiz.GetBiz(ct, HttpContext);
            if (!Authorized.HasModifyRole(HttpContext.Items, biz.BizType))
                return StatusCode(403, new ApiNotAuthorizedResponse());
            var o = await biz.PutAsync(updatedObject);//In future may need to return entire object, for now just concurrency token 
            if (o == null)
            {
                if (biz.Errors.Exists(z => z.Code == ApiErrorCode.CONCURRENCY_CONFLICT))
                    return StatusCode(409, new ApiErrorResponse(biz.Errors));
                else
                    return BadRequest(new ApiErrorResponse(biz.Errors));
            }
            return Ok(ApiOkResponse.Response(new { Concurrency = o.Concurrency })); 
        }

        /// <summary>
        /// Delete Widget
        /// </summary>
        /// <param name="id"></param>
        /// <returns>NoContent</returns>
        [HttpDelete("{id}")]
        public async Task<IActionResult> DeleteWidget([FromRoute] long id)
        {
            if (!serverState.IsOpen)
                return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
            if (!ModelState.IsValid)
                return BadRequest(new ApiErrorResponse(ModelState));
            WidgetBiz biz = WidgetBiz.GetBiz(ct, HttpContext);
            if (!Authorized.HasDeleteRole(HttpContext.Items, biz.BizType))
                return StatusCode(403, new ApiNotAuthorizedResponse());
            if (!await biz.DeleteAsync(id))
                return BadRequest(new ApiErrorResponse(biz.Errors));
            return NoContent();
        }


        /// <summary>
        /// ReStart serial number
        /// 
        /// </summary>
        /// <param name="newSerial">Next starting value for auto generated serial numbers</param>
        /// <param name="apiVersion">From route path</param>
        /// <returns>Widget</returns>
        [HttpPost("restart-serial/{newSerial}")]
        public async Task<IActionResult> ReStartSerial([FromRoute] long newSerial, ApiVersion apiVersion)
        {
            if (!serverState.IsOpen)
                return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
            WidgetBiz biz = WidgetBiz.GetBiz(ct, HttpContext);
            if (!Authorized.HasCreateRole(HttpContext.Items, biz.BizType))
                return StatusCode(403, new ApiNotAuthorizedResponse());
            if (!ModelState.IsValid)
                return BadRequest(new ApiErrorResponse(ModelState));
            bool result=await biz.RestartSerial(newSerial);
            if (!result)
                return BadRequest(new ApiErrorResponse(biz.Errors));
            else
                return NoContent();
        }


        ///////////////////////////////////////////////
        //TEST ROUTES
        //

        /// <summary>
        /// Get route that triggers exception for testing
        /// </summary>
        /// <returns>Nothing, triggers exception</returns>
        [HttpGet("exception")]
        public ActionResult GetException()
        {
            //log.LogInformation("Widget::getexception-> Test exception and log from controller test");
            if (!serverState.IsOpen)
                return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
            throw new System.NotSupportedException("Test exception from widget controller");
        }

        /// <summary>
        /// Get route that triggers an alternate type of exception for testing
        /// </summary>
        /// <returns>Nothing, triggers exception</returns>
        [HttpGet("altexception")]
        public ActionResult GetAltException()
        {
            if (!serverState.IsOpen)
                return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
            throw new System.ArgumentException("Test exception (ALT) from widget controller");
        }


       

        //------------


    }//eoc
}//eons