using EVCB_OCPP.WEBAPI.Handlers;
using EVCB_OCPP.WEBAPI.Models.WebAPI;
using EVCB_OCPP.WEBAPI.Models.WebAPI.Dto;
using EVCB_OCPP.WEBAPI.Services;
using EVCB_OCPP.WEBAPI.Services.Integration;
using EVCB_OCPP20.Packet.Messages;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using ServerTriggerService = EVCB_OCPP.WEBAPI.Services.Integration.ServerTriggerService;
using Microsoft.Extensions.DependencyInjection;

namespace EVCB_OCPP.WEBAPI.Controllers.Version2.ocpp201
{
    [ApiExplorerSettings(IgnoreApi = false)]
    [Route("api/v2/cpo201")]
    [ServiceFilter(typeof(CPOAuthentication))]
    //[CPOAuthentication]
    public class OCPP201_CPOController : ControllerBase
    {
        private HttpClientService service = new HttpClientService();
        private readonly IServiceProvider serviceProvider;

        public OCPP201_CPOController(IServiceProvider serviceProvider)
        {
            this.serviceProvider = serviceProvider;
        }

        private bool ContainsChargePoint(string chargeBoxId, out string customerId)
        {
            customerId = string.Empty;

            if (!Request.Headers.ContainsKey(EVCBConfiguration.Header_PartnerId)) return false;

            customerId = Request.Headers[EVCBConfiguration.Header_PartnerId].First();

            ChargePoint201Service _service = serviceProvider.GetRequiredService<ChargePoint201Service>();
            return _service.ContainsChargePoint(chargeBoxId, customerId);

        }
      
        [Route("commands/chargingprofiles")]
        [Produces(typeof(CPOOuterResponse))]
        [HttpPut]
        async public Task<IActionResult> SetChargingProfile(string ChargeBoxId, [FromBody] ChargingProfileRequest request)
        {
            var result = new CPOOuterResponse();
            //HttpStatusCode statusCode = HttpStatusCode.InternalServerError;
            int statusCode = StatusCodes.Status500InternalServerError;
            var _innerData = new { Result = CommandResponseType.Rejected.ToString(), Timeout = 60 };
            try
            {
                string _CustomerId = string.Empty;

                if (!ContainsChargePoint(ChargeBoxId, out _CustomerId))
                {
                    // 沒槍~ 沒得充...                   
                    result.StatusMessage = CPO_StatusMessage.ERROR_MSG_CHARGEBOXID_DOESNT_EXIST;
                    result.StatusCode = (int)CPO_StatusCode.CHARGEBOXID_ISNT_EXIST_OR_OFFLINE;
                    result.Data = JsonConvert.SerializeObject(_innerData, EVCBConfiguration.JSONSERIALIZER_FORMAT);
                    //statusCode = HttpStatusCode.BadRequest;
                    statusCode = StatusCodes.Status400BadRequest;
                    return StatusCode(statusCode, result);
                }



                InternalHttpClient _client = serviceProvider.GetRequiredService<InternalHttpClient>();
                ICustomerService _customer = serviceProvider.GetRequiredService<ICustomerService>();

                string urlformat = "{0}://{1}";

                var _innerResult = await _client.Post(
                    string.Format(urlformat, Request.Scheme, Request.Host.ToUriComponent()), 
                    $"/api/v1/ocpp20/chargingprofile?ChargeBoxId={ChargeBoxId}",
                    new Dictionary<string, string>()
                        {
                            { "PartnerId",_CustomerId}

                        }, request, _customer.GetAPIKey(new Guid(_CustomerId)));


                _innerData = new { Result = string.IsNullOrEmpty(_innerResult.SerialNo) ? CommandResponseType.Rejected.ToString() : CommandResponseType.Accepted.ToString(), Timeout = 60 };
                result = GetErrorDescription(_innerResult);
                result.Data = JsonConvert.SerializeObject(_innerData, EVCBConfiguration.JSONSERIALIZER_FORMAT);
                if (_innerResult.Success)
                {
                    result.SerialNo = _innerResult.SerialNo;
                    result.StatusCode = (int)CPO_StatusCode.Success;
                    result.StatusMessage = CPO_StatusMessage.Success;
                    //statusCode = HttpStatusCode.OK;
                    statusCode = StatusCodes.Status200OK;
                }
                else
                {

                    result.StatusCode = _innerResult.ErrorCode;
                    result.StatusMessage = CPO_StatusMessage.ERROR_MSG_INNERSERVICE_ERROR;
                    //statusCode = HttpStatusCode.BadRequest;
                    statusCode = StatusCodes.Status400BadRequest;
                }
                ChargePoint201Service ChargePoint201Service = serviceProvider.GetRequiredService<ChargePoint201Service>();

                if (!ChargePoint201Service.IsOnline(ChargeBoxId))
                {
                    return StatusCode(StatusCodes.Status400BadRequest, new ErrorResponse() { Code = 2101, Message = EVCBConfiguration.ERROR_MSG_CHARGEBOXID_ISNT_EXIST_OR_OFFLINE });
                }


            }
            catch (Exception ex)
            {
                result.ErrorDetail = ex.ToString();
                result.StatusMessage = CPO_StatusMessage.ERROR_MSG_UNEXPECTEDERROR;
                result.StatusCode = (int)CPO_StatusCode.UnexpectedError;
                return StatusCode(statusCode, result);
            }

            return StatusCode(statusCode, result);
        }



        [Route("commands/chargingprofiles")]
        [Produces(typeof(CPOOuterResponse))]
        [HttpDelete]
        async public Task<IActionResult> ClearChargingPorfile(string ChargeBoxId, int ChargeProfileId = -1)
        {
            var result = new CPOOuterResponse();
            //HttpStatusCode statusCode = HttpStatusCode.InternalServerError;
            int statusCode = StatusCodes.Status500InternalServerError;
            var _innerData = new { Result = CommandResponseType.Rejected.ToString(), Timeout = 60 };
            try
            {
                string _CustomerId = string.Empty;

                if (!ContainsChargePoint(ChargeBoxId, out _CustomerId))
                {
                    // 沒槍~ 沒得充...                   
                    result.StatusMessage = CPO_StatusMessage.ERROR_MSG_CHARGEBOXID_DOESNT_EXIST;
                    result.StatusCode = (int)CPO_StatusCode.CHARGEBOXID_ISNT_EXIST_OR_OFFLINE;
                    result.Data = JsonConvert.SerializeObject(_innerData, EVCBConfiguration.JSONSERIALIZER_FORMAT);
                    //statusCode = HttpStatusCode.BadRequest;
                    statusCode = StatusCodes.Status400BadRequest;
                    return StatusCode(statusCode, result);
                }


                InternalHttpClient _client = serviceProvider.GetRequiredService<InternalHttpClient>();
                ICustomerService _customer = serviceProvider.GetRequiredService<ICustomerService>();

                string urlformat = "{0}://{1}";

                var _innerResult = await _client.Delete(
                    string.Format(urlformat, Request.Scheme, Request.Host.ToUriComponent()),
                    string.Format("/api/v1/ocpp20/chargingprofile?ChargeBoxId={0}{1}", ChargeBoxId, ChargeProfileId == -1 ? "" : "&Id=" + ChargeProfileId),
                    new Dictionary<string, string>()
                    {
                        { "PartnerId",_CustomerId}

                    }, _customer.GetAPIKey(new Guid(_CustomerId)));


                _innerData = new { Result = string.IsNullOrEmpty(_innerResult.SerialNo) ? CommandResponseType.Rejected.ToString() : CommandResponseType.Accepted.ToString(), Timeout = 60 };
                result = GetErrorDescription(_innerResult);
                result.Data = JsonConvert.SerializeObject(_innerData, EVCBConfiguration.JSONSERIALIZER_FORMAT);
                if (_innerResult.Success)
                {
                    result.SerialNo = _innerResult.SerialNo;
                    result.StatusCode = (int)CPO_StatusCode.Success;
                    result.StatusMessage = CPO_StatusMessage.Success;
                    //statusCode = HttpStatusCode.OK;
                    statusCode = StatusCodes.Status200OK;
                }
                else
                {

                    result.StatusCode = _innerResult.ErrorCode;
                    result.StatusMessage = CPO_StatusMessage.ERROR_MSG_INNERSERVICE_ERROR;
                    //statusCode = HttpStatusCode.BadRequest;
                    statusCode = StatusCodes.Status400BadRequest;
                }
            }
            catch (Exception ex)
            {
                result.ErrorDetail = ex.ToString();
                result.StatusMessage = CPO_StatusMessage.ERROR_MSG_UNEXPECTEDERROR;
                result.StatusCode = (int)CPO_StatusCode.UnexpectedError;
                return StatusCode(statusCode, result);
            }

            return StatusCode(statusCode, result);
        }

        [Route("commands/max_limit")]
        [Produces(typeof(CPOOuterResponse))]
        [HttpDelete]
        async public Task<IActionResult> SetMaxLimit(string ChargeBoxId, int MaxCharginCurrent = 0, int MaxCharginPower = 0, int MaxChargingEnergy = 0)
        {
            var result = new CPOOuterResponse();
            //HttpStatusCode statusCode = HttpStatusCode.InternalServerError;
            int statusCode = StatusCodes.Status500InternalServerError;
            var _innerData = new { Result = CommandResponseType.Rejected.ToString(), Timeout = 60 };
            try
            {
                string _CustomerId = string.Empty;

                if (!ContainsChargePoint(ChargeBoxId, out _CustomerId))
                {
                    // 沒槍~ 沒得充...                   
                    result.StatusMessage = CPO_StatusMessage.ERROR_MSG_CHARGEBOXID_DOESNT_EXIST;
                    result.StatusCode = (int)CPO_StatusCode.CHARGEBOXID_ISNT_EXIST_OR_OFFLINE;
                    result.Data = JsonConvert.SerializeObject(_innerData, EVCBConfiguration.JSONSERIALIZER_FORMAT);
                    //statusCode = HttpStatusCode.BadRequest;
                    statusCode = StatusCodes.Status400BadRequest;
                    return StatusCode(statusCode, result);
                }


                InternalHttpClient _client = serviceProvider.GetRequiredService<InternalHttpClient>();
                ICustomerService _customer = serviceProvider.GetRequiredService<ICustomerService>();

                string urlformat = "{0}://{1}";

                var _innerResult = await _client.Post(
                    string.Format(urlformat, Request.Scheme, Request.Host.ToUriComponent()),
                    $"/api/v1/ocpp20/datatransfer?ChargeBoxId={ChargeBoxId}&MessageId=ID_CpConfiguration",
                    new Dictionary<string, string>()
                        {
                            { "PartnerId",_CustomerId}

                        }, JsonConvert.SerializeObject(new
                        {
                            OfflinePolicy = 0,
                            OfflineMaxChargeEnergy = 0,
                            MaxChargingCurrent = MaxCharginCurrent,
                            MaxChargingDuration = 0,
                            MaxChargingEnergy = MaxChargingEnergy,
                            MaxChargingPower = MaxCharginPower,

                        }), _customer.GetAPIKey(new Guid(_CustomerId)));


                _innerData = new { Result = string.IsNullOrEmpty(_innerResult.SerialNo) ? CommandResponseType.Rejected.ToString() : CommandResponseType.Accepted.ToString(), Timeout = 60 };
                result = GetErrorDescription(_innerResult);
                result.Data = JsonConvert.SerializeObject(_innerData, EVCBConfiguration.JSONSERIALIZER_FORMAT);
                if (_innerResult.Success)
                {
                    result.SerialNo = _innerResult.SerialNo;
                    result.StatusCode = (int)CPO_StatusCode.Success;
                    result.StatusMessage = CPO_StatusMessage.Success;
                    //statusCode = HttpStatusCode.OK;
                    statusCode = StatusCodes.Status200OK;
                }
                else
                {

                    result.StatusCode = _innerResult.ErrorCode;
                    result.StatusMessage = CPO_StatusMessage.ERROR_MSG_INNERSERVICE_ERROR;
                    //statusCode = HttpStatusCode.BadRequest;
                    statusCode = StatusCodes.Status400BadRequest;
                }
            }
            catch (Exception ex)
            {
                result.ErrorDetail = ex.ToString();
                result.StatusMessage = CPO_StatusMessage.ERROR_MSG_UNEXPECTEDERROR;
                result.StatusCode = (int)CPO_StatusCode.UnexpectedError;
                return StatusCode(statusCode, result);
            }

            return StatusCode(statusCode, result);
        }
         
        private bool AddCommandtoServer(string chargeBoxId, string uuid, IRequest request)
        {
            bool result = false;
            try
            {
                ServerTriggerService service = serviceProvider.GetRequiredService<ServerTriggerService>();
                service.AddMessage(chargeBoxId, uuid, request);
                result = true;
            }
            catch (Exception ex)
            {
                ;
            }

            return result;
        }


        private CPOOuterResponse GetErrorDescription(InternalHttpResult innerResponse)
        {
            CPOOuterResponse result = new CPOOuterResponse();

            result.ErrorDetail = innerResponse.Exception == null ? null : innerResponse.Exception.ToString();

            if (innerResponse.Status != HttpStatusCode.Accepted)
            {
                switch (innerResponse.ErrorCode)
                {
                    #region Authorization
                    case 2000:
                        {
                            result.StatusCode = innerResponse.ErrorCode;
                            result.StatusMessage = string.Format("{0}-{1}", "InnerService", "Authorize Unexpected Error");
                            result.ErrorDetail = result.StatusMessage;
                        }
                        break;
                    case 2001:
                    case 2002:
                    case 2003:
                        {
                            result.StatusCode = innerResponse.ErrorCode;
                            result.StatusMessage = string.Format("{0}-{1}", "InnerService", innerResponse.Message);
                        }
                        break;

                    #endregion
                    case 2100:
                    case 2101:
                    case 2102:
                    case 2103:
                    case 2104:
                    case 2105:
                    case 2106:
                        {
                            result.StatusCode = innerResponse.ErrorCode;
                            result.StatusMessage = innerResponse.Message;
                        }
                        break;
                    case 2999:
                        {
                            result.StatusCode = innerResponse.ErrorCode;
                            result.StatusMessage = string.Format("{0}-{1}", "InnerService", "Unexpected Error");
                            result.ErrorDetail = result.StatusMessage;
                        }
                        break;
                    default:
                        {
                            result.StatusCode = 2998;
                            result.StatusMessage = CPO_StatusMessage.ERROR_MSG_CANT_FIND_ERRORCODE;
                        }
                        break;
                }
            }

            return result;


        }

    }
}
