using AyCode.Utils.Extensions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System.Linq.Expressions;
using System.Reflection.Metadata;
using System.Text.Json;
using TIAM.Core.Enums;
using TIAM.Database.DataLayers;
using TIAM.Database.DataLayers.Admins;
using TIAM.Database.DataLayers.TransferDestinations;
using TIAM.Database.DataLayers.Users;
using TIAM.Database.DbContexts;
using TIAM.Database.DbSets.Transfers;
using TIAM.Entities.Products;
using TIAM.Entities.Transfers;
using TIAM.Entities.Users;
using TIAMWebApp.Server.Services;
using TIAMWebApp.Shared.Application.Models;
using TIAMWebApp.Shared.Application.Models.ClientSide.UI.WizardModels;
using TIAMWebApp.Shared.Application.Models.PageModels;

namespace TIAMWebApp.Server.Controllers
{
    [ApiController]
    [Route("api/v1/[controller]")]
    public class TransferDataAPIController : ControllerBase
    {
        //private static readonly TransferDestination[] Names = new TransferDestination[]
        //{
        //    /*"Castle of Buda", "Hungarian National Museum", "Parliament of Hungary", "Heroes square", "Gellert Hill", "Margaret Island"*/
        //    new() { DestinationId = 1, DestinationName = "Airport", DestinationDescription = "International airport of Budapest", DestinationLatitude = 42.234444f, DestinationLongitude = 39.100010f },
        //    new() { DestinationId = 2, DestinationName = "Castle of Buda", DestinationDescription = "International airport of Budapest", DestinationLatitude = 42.234444f, DestinationLongitude = 39.100010f },
        //    new() { DestinationId = 3, DestinationName = "Hungarian National Museum", DestinationDescription = "International airport of Budapest", DestinationLatitude = 42.234444f, DestinationLongitude = 39.100010f },
        //    new() { DestinationId = 4, DestinationName = "Parliament of Hungary", DestinationDescription = "International airport of Budapest", DestinationLatitude = 42.234444f, DestinationLongitude = 39.100010f },
        //    new() { DestinationId = 5, DestinationName = "Heroes square", DestinationDescription = "International airport of Budapest", DestinationLatitude = 42.234444f, DestinationLongitude = 39.100010f },
        //    new() { DestinationId = 6, DestinationName = "Gellert Hill", DestinationDescription = "International airport of Budapest", DestinationLatitude = 42.234444f, DestinationLongitude = 39.100010f },
        //    new() { DestinationId = 6, DestinationName = "Margaret Island", DestinationDescription = "International airport of Budapest", DestinationLatitude = 42.234444f, DestinationLongitude = 39.100010f }

        //};

        private readonly TransferDestinationDal _transferDestinationDal;
        private readonly AdminDal _adminDal;
        private readonly ILogger<TransferDataAPIController> _logger;
        private readonly TransferBackendService _transferBackendService;

        public TransferDataAPIController(ILogger<TransferDataAPIController> logger, TransferDestinationDal transferDestinationDal, AdminDal adminDal, TransferBackendService transferBackendService)
        {
            _logger = logger;
            _transferDestinationDal = transferDestinationDal;
            _adminDal = adminDal;
            _transferBackendService = transferBackendService;
        }

        

        [AllowAnonymous]
        [HttpGet]
        [Route(APIUrls.GetTransferDestinationsRouteName)]
        public async Task<IEnumerable<TransferDestination>> GetTransferDestinations()
        {
            return await _adminDal.Context.TransferDestinations.ToListAsync();
        }

        [AllowAnonymous]
        [HttpGet]
        [Route("GetTransferDestinationByCoordinates")]
        public async Task<TransferDestination?> GetTransferDestinationByCoordinates(double latitude, double longitude)
        {
            return null;// await _transferDestinationDal.Context.TransferDestinations.FirstOrDefaultAsync(x => x.Latitude == latitude && x.Longitude == longitude);
        }

        [AllowAnonymous]
        [HttpGet]
        [Route("GetTransferDestinationByAddress")]
        public async Task<TransferDestination?> GetTransferDestinationByAddress(string address)
        {
            return null;//await _transferDestinationDal.Context.TransferDestinations.FirstOrDefaultAsync(x => x.Address == address);
        }

        [AllowAnonymous]
        [HttpPost]
        [Route(APIUrls.CreateTransferDestinationRouteName)]
        public async Task<IActionResult> CreateTransferDestination([FromBody] JsonElement serializedTransferDestinationModel)
        {
            Console.WriteLine("CreateTransferDestination called!");
            if (string.IsNullOrEmpty(serializedTransferDestinationModel.GetRawText()))
            {
                return BadRequest("SerializedTramsferDestinationWizardModel is required");
            }
            else
            {
                TransferDestination? transferDestination = JObject.Parse(serializedTransferDestinationModel.GetRawText()).ToObject<TransferDestination>();

                if (transferDestination != null)
                {
                    
                    var id = Guid.NewGuid();
                    //TransferDestination transferDestination = new TransferDestination(id, transferDestinationModel.Name, transferDestinationModel.Description, transferDestinationModel.AddressString);
                    

                    if (string.IsNullOrEmpty(transferDestination.Name) || string.IsNullOrEmpty(transferDestination.AddressString))
                    {
                        return BadRequest("Invalid request");
                    }
                    else
                    {
                        Console.WriteLine($"TransferDestination to be created: {id}");
                        Console.WriteLine($"TransferDestination to be created: {transferDestination.AddressId}");
                        Console.WriteLine($"TransferDestination to be created: {transferDestination.Name}");
                        Console.WriteLine($"TransferDestination to be created: {transferDestination.Price}");
                        Console.WriteLine($"TransferDestination to be created: {transferDestination.Price2}");
                        Console.WriteLine($"TransferDestination to be created: {transferDestination.Price3}");
                        Console.WriteLine($"TransferDestination to be created: {transferDestination.ExtraPrice}");
                        Console.WriteLine($"TransferDestination to be created: {transferDestination.ExtraPriceType}");
                        Console.WriteLine($"TransferDestination to be created: {transferDestination.AddressString}");
                        Console.WriteLine($"TransferDestination to be created: {transferDestination.Description}");                        

                        //await _transferDestinationDal.Context.TransferDestinations.AddAsync(transferDestination);
                        await _adminDal.AddTransferDestinationAsync(transferDestination);
                        return Ok(transferDestination);
                    }
                }
                else
                {
                    return BadRequest("Invalid request");
                }
               

            }


        }

        [AllowAnonymous]
        [HttpPost]
        [Route(APIUrls.UpdateTransferDestinationRouteName)]
        public async Task<IActionResult> UpdateTransferDestination([FromBody]JsonElement serializedTransferDestination)
        {
            Console.WriteLine("UpdateTransferDestination called!");
            if (string.IsNullOrEmpty(serializedTransferDestination.GetRawText()))
            {
                Console.WriteLine("Bad request!");
                return BadRequest("SerializedTramsferDestinationWizardModel is required");
            }
            else
            {
                Console.WriteLine("Serialized model not empty!");
                TransferDestination? transferDestination = JObject.Parse(serializedTransferDestination.GetRawText()).ToObject<TransferDestination>();
                Console.WriteLine($"TransferDestination to be updated: {serializedTransferDestination.GetRawText()}");
                Console.WriteLine($"TransferDestination to be updated: {transferDestination.AddressString}");


                if (transferDestination != null)
                {

                    
                    //TransferDestination transferDestination = new TransferDestination(id, transferDestinationModel.Name, transferDestinationModel.Description, transferDestinationModel.AddressString);

                    if (transferDestination.Id == Guid.Empty || string.IsNullOrEmpty(transferDestination.Name) || string.IsNullOrEmpty(transferDestination.AddressString))
                    {
                        Console.WriteLine("Serialized model not empty, but bad request!");
                        return BadRequest("Invalid request");
                    }
                    else
                    {

                        Console.WriteLine($"TransferDestination to be updated: {transferDestination.Id}");
                        Console.WriteLine($"TransferDestination to be updated new name: {transferDestination.Name}");
                        Console.WriteLine($"TransferDestination to be updated new price: {transferDestination.Price}");
                        //Console.WriteLine($"TransferDestination to be updated new price: {transferDestination.Price2}");
                        //Console.WriteLine($"TransferDestination to be updated new price: {transferDestination.Price3}");
                        //Console.WriteLine($"TransferDestination to be updated new priceType: {transferDestination.PriceType}");
                        Console.WriteLine($"TransferDestination to be updated new address: {transferDestination.AddressString}");
                        Console.WriteLine($"TransferDestination to be updated new description: {transferDestination.Description}");

                        //var dbTransferDestinationJson = _adminDal.GetTransferDestinationJsonById(transferDestination.Id);
                        //Console.WriteLine($"TransferDestination JSON to be updated: {dbTransferDestinationJson}");

                        //var dbTransferDestination = JObject.Parse(dbTransferDestinationJson).ToObject<TransferDestination>();

                        //var dbTransferDestination = _adminDal.GetTransferDestinationById(transferDestination.Id, true);
                        //if (dbTransferDestination.Id != Guid.Empty)
                        //{
                        //    dbTransferDestination.AddressId = transferDestination.AddressId;
                        //    dbTransferDestination.Price = transferDestination.Price;
                        //    dbTransferDestination.PriceType = transferDestination.PriceType;
                        //    dbTransferDestination.Name = transferDestination.Name;
                        //    dbTransferDestination.Description = transferDestination.Description;
                        //    dbTransferDestination.AddressString = transferDestination.AddressString;
                        //    dbTransferDestination.Address = transferDestination.Address;
                            
                        //}

                        //await _transferDestinationDal.Context.TransferDestinations.AddAsync(transferDestination);
                        await _adminDal.UpdateTransferDestinationAsync(transferDestination);
                        return Ok(transferDestination);
                    }
                }
                else
                {
                    return BadRequest("Invalid request");
                }


            }


        }

        [AllowAnonymous]
        [HttpPost]
        [Route(APIUrls.CreateTransferRouteName)]
        public async Task<IActionResult> CreateTransfer([FromBody] JsonElement serializedTransferModel)
        {
            Console.WriteLine("CreateTransfer called!");
            if (string.IsNullOrEmpty(serializedTransferModel.GetRawText()))
            {
                return BadRequest("SerializedTramsferDestinationWizardModel is required");
            }
            else
            {
                Transfer? transfer= JObject.Parse(serializedTransferModel.GetRawText()).ToObject<Transfer>();

                if (transfer != null)
                {

                    var id = Guid.NewGuid();
                    //TransferDestination transferDestination = new TransferDestination(id, transferDestinationModel.Name, transferDestinationModel.Description, transferDestinationModel.AddressString);


                    if (string.IsNullOrEmpty(transfer.FromAddress) || string.IsNullOrEmpty(transfer.ToAddress))
                    {
                        return BadRequest("Invalid request");
                    }
                    else
                    {
                        Console.WriteLine($"TransferDestination to be created: {id}");
                        Console.WriteLine($"TransferDestination to be created: {transfer.FromAddress}");
                        Console.WriteLine($"TransferDestination to be created: {transfer.ToAddress}");
                        Console.WriteLine($"TransferDestination to be created: {transfer.ProductId}");
                        Console.WriteLine($"TransferDestination to be created: {transfer.Price}");

                        var from = await _adminDal.Context.TransferDestinations.FirstOrDefaultAsync(x => x.AddressString == transfer.FromAddress);
                        var to = await _adminDal.Context.TransferDestinations.FirstOrDefaultAsync(x => x.AddressString == transfer.ToAddress);
                        
                        //TODO 
                        if(!transfer.ProductId.IsNullOrEmpty())
                            transfer.Price = _transferBackendService.GetTransferPrice(transfer.ProductId.Value, from, to, transfer.PassengerCount);
                        
                        transfer.TransferStatusType = TransferStatusType.OrderSubmitted;
                        
                        await _adminDal.AddTransferAsync(transfer);
                        return Ok(transfer);
                    }
                }
                else
                {
                    return BadRequest("Invalid request");
                }


            }


        }

        [AllowAnonymous]
        [HttpPost]
        [Route(APIUrls.CreateTransfersRouteName)]
        public async Task<IActionResult> CreateTransfers([FromBody] JsonElement serializedTransferModel)
        {
            Console.WriteLine("CreateTransfers called!");
            if (string.IsNullOrEmpty(serializedTransferModel.GetRawText()))
            {
                return BadRequest("SerializedTramsferDestinationWizardModel is required");
            }
            else
            {
                Console.WriteLine($"Serialized model: {serializedTransferModel.GetRawText()}");

                var settings = new JsonSerializerSettings
                {
                    ContractResolver = new CamelCasePropertyNamesContractResolver()
                };

                List<Transfer>? transfers = JsonConvert.DeserializeObject<List<Transfer>>(serializedTransferModel.GetRawText(), settings);

                //List<Transfer>? transfers = JObject.Parse(serializedTransferModel.GetRawText()).ToObject<List<Transfer>>();
                List<Transfer> createdTransfers = new List<Transfer>();
                if (transfers != null)
                {
                    foreach (var transfer in transfers)
                    {
                        var id = Guid.NewGuid();
                        var result = await _adminDal.AddTransferAsync(transfer);
                        if(result)
                        {
                            createdTransfers.Add(transfer);
                        }
                    }
                    return Ok(createdTransfers);
                }
                else
                {
                    return BadRequest("Invalid request");
                }
            }
        }

        [AllowAnonymous]
        [HttpGet]
        [Route(APIUrls.GetTransfersRouteName)]
        public async Task<string> GetTransfers()
        {
            var result = await _adminDal.GetTransfersJsonAsync();

            return result;            
        }

    }
}