﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Web.Http;
using AutoMapper;
using Sentinel.KeyVault;
using Sentinel.Sample.API.Contracts;
using Sentinel.Sample.API.TableStorage;
using Sentinel.Sample.API.TableStorage.Entities;
using Swashbuckle.Swagger.Annotations;

namespace Sentinel.Sample.API.Controllers
{
    [RoutePrefix("api/v1/orders")]
    public class OrderController : ApiController
    {
        /// <summary>
        ///     Creates a new order
        /// </summary>
        /// <param name="orderRequest">Request describing what they want to order</param>
        /// <returns></returns>
        [SwaggerResponse(HttpStatusCode.OK, "Order was successfully placed", typeof(OrderConfirmation))]
        [SwaggerResponse(HttpStatusCode.BadRequest, "Order request was not valid", typeof(List<string>))]
        [SwaggerResponse(HttpStatusCode.InternalServerError, "Unable to process the order request")]
        [HttpPost]
        public async Task<IHttpActionResult> Post([FromBody] OrderRequest orderRequest)
        {
            var validationResults = Validate(orderRequest);
            if (validationResults.Any())
            {
                return BadRequest($"Request was invalid. Reason: {string.Join(", ", validationResults)}.");
            }

            // Generate a new confirmation Id
            var confirmationId = Guid.NewGuid().ToString("N").ToUpper();

            // Store request in Azure Table Storage
            await StoreOrderRequestInTableStorage(orderRequest, confirmationId);

            OrderConfirmation confirmation = ComposeOrderConfirmation(orderRequest, confirmationId);

            return Ok(confirmation);
        }

        private async Task StoreOrderRequestInTableStorage(OrderRequest orderRequest, string confirmationId)
        {
            OrderRequestTableEntity tableEntity = ComposeTableEntity(orderRequest, confirmationId);

            var storageConnectionString = await KeyVaultGateway.Instance.GetSecretAsync("Order-Request-Storage");
            var tableStorageClient = new TableStorageClient(storageConnectionString);
            await tableStorageClient.InsertAsync("OrderRequests", tableEntity);
        }

        private static OrderRequestTableEntity ComposeTableEntity(OrderRequest orderRequest, string confirmationId)
        {
            var orderRequestTableEntity = Mapper.Map<OrderRequest, OrderRequestTableEntity>(orderRequest);
            orderRequestTableEntity.PartitionKey = orderRequest.CustomerName;
            orderRequestTableEntity.RowKey = confirmationId;

            return orderRequestTableEntity;
        }

        private static OrderConfirmation ComposeOrderConfirmation(OrderRequest orderRequest, string confirmationId)
        {
            var orderConfirmation = Mapper.Map<OrderRequest, OrderConfirmation>(orderRequest);
            orderConfirmation.ConfirmationId = confirmationId;

            return orderConfirmation;
        }

        private List<string> Validate(OrderRequest orderRequest)
        {
            var validationResults = new List<string>();

            if (orderRequest == null)
            {
                validationResults.Add("Order request was not specified");
            }
            else
            {
                if (orderRequest.Amount < 1)
                {
                    validationResults.Add("At least one product needs to be ordered");
                }
                if (string.IsNullOrWhiteSpace(orderRequest.CustomerName))
                {
                    validationResults.Add("Customer name is not specified");
                }
                if (string.IsNullOrWhiteSpace(orderRequest.ProductName))
                {
                    validationResults.Add("No product name was specified");
                }
            }

            return validationResults;
        }
    }
}