using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Italia.DiciottoApp.Data;
using Italia.DiciottoApp.DTOs;
using Italia.DiciottoApp.Models;
using Italia.DiciottoApp.Utils;
using Newtonsoft.Json;

namespace Italia.DiciottoApp.Services
{
    public class VouchersService : IVouchersService
    {
        private HttpClient httpClient;
        private readonly CultureInfo ci = new CultureInfo("it-IT");

        public string ClientId { get; set; } = Settings.IsProductionEnvironment ? Keys.X_IBM_ClientId_ProdEnv : Keys.X_IBM_ClientId_TestEnv;

        public string ClientSecret { get; set; } = Settings.IsProductionEnvironment ? Keys.X_IBM_ClientSecret_ProdEnv : Keys.X_IBM_ClientSecret_TestEnv;

        public async Task<IEnumerable<Voucher>> GetUserVouchersAsync(Cookie fedSecureToken, bool spent, int page = 0, int pageItems = 100, CancellationToken ct = default)
        {
            List<Voucher> vouchers = new List<Voucher>();

            // Check for cancellation
            if (ct.IsCancellationRequested)
            {
                Debug.WriteLine("[RicercaStoreByFilterAsync] Cancellation requested during task execution.");
                ct.ThrowIfCancellationRequested();
            }

            String serviceEndpoint = Settings.IsProductionEnvironment ? Constants.SERVICE_ENDPOINT_ProdEnv : Constants.SERVICE_ENDPOINT_TestEnv;

            httpClient = HttpClientFactory.Builder(ClientId, ClientSecret, fedSecureToken);

            var serviceResult = new ServiceResult<VoucherByBeneficiarioBean>();

            try
            {
                string servicePath = spent ? "listaVoucherSpesi" : "listaVoucherDaSpendere";
                var response = await httpClient.GetAsync($"{serviceEndpoint}/BONUSWS/rest/secured/18enne/{servicePath}", ct);
                await serviceResult.ProcessAsync(response);
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"++++ RicercaStoreByFilterAsync error: {ex.Message}");
            }

            if (!serviceResult.Success)
            {
                Debug.WriteLine($"++++ RicercaStoreByFilterAsync result error: {serviceResult.FailureReason}");
                foreach (var response in serviceResult.Log)
                {
                    Debug.WriteLine($"  ++ service operation: {response.RequestMessage.RequestUri} , result: {response.StatusCode}");
                }
            }

            // Check for cancellation
            if (ct.IsCancellationRequested)
            {
                Debug.WriteLine("[FindShopsAsync] Cancellation requested during task execution.");
                ct.ThrowIfCancellationRequested();
            }

            if (serviceResult.Success)
            {
                if (serviceResult.Result?.ListaVoucherFisico != null)
                {
                    foreach (var voucherBean in serviceResult.Result.ListaVoucherFisico)
                    {
                        // vouchers.Add(Voucher.FromVoucherBean(voucherBean, online: false, spent: spent));
                        vouchers.Add(Voucher.FromVoucherBean(voucherBean, online: false));
                    }
                }

                if (serviceResult.Result?.ListaVoucherOnline != null)
                {
                    foreach (var voucherBean in serviceResult.Result.ListaVoucherOnline)
                    {
                        // vouchers.Add(Voucher.FromVoucherBean(voucherBean, online: true, spent: spent));
                        vouchers.Add(Voucher.FromVoucherBean(voucherBean, online: true));
                    }
                }
            }

            return vouchers;
        }

        public async Task<ServiceResult<VoucherBean>> CreateVoucherAsync(Cookie fedSecureToken, Categoria categoria, Prodotto prodotto, double valore, bool online)
        {
            if (categoria == null)
            {
                throw new ArgumentNullException(message:"Non è stata scelta la categoria", null);
            }

            if (prodotto == null)
            {
                throw new ArgumentNullException(message:"Non è stato scelto il prodotto", null);
            }

            if (valore <= 0 || valore > Constants.NEW_VOUCHER_MAX_VALUE)
            {
                throw new ArgumentOutOfRangeException(message: $"Il valore dev'essere maggiore di zero e minore uguale a {Constants.NEW_VOUCHER_MAX_VALUE.ToString("###.##", ci)}", null);
            }

            VoucherBean voucherBean = new VoucherBean
            {
                AmbitoBean = AmbitoBeanFromCategoria(categoria),
                BeneBean = BeneBeanFromProdotto(prodotto),
                BeneficiarioBean = Settings.GetBeneficiario(),
                ImportoRichiesto = valore
            };

            String serviceEndpoint = Settings.IsProductionEnvironment ? Constants.SERVICE_ENDPOINT_ProdEnv : Constants.SERVICE_ENDPOINT_TestEnv;
            httpClient = HttpClientFactory.Builder(ClientId, ClientSecret, fedSecureToken);
            var createVoucherServiceResult = new ServiceResult<VoucherBean>();

            try
            {
                // Creazione del body content
                string ricercaStoreBeanJson = JsonConvert.SerializeObject(voucherBean);
                StringContent httpContent = new StringContent(ricercaStoreBeanJson, Encoding.UTF8, "application/json");

                // Recupero i dati della ricerca store
                var response = await httpClient.PostAsync($"{serviceEndpoint}/BONUSWS/rest/secured/18enne/insVoucher{(online ? "Online" : "Fisico")}", httpContent);
                await createVoucherServiceResult.ProcessAsync(response);
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"++++ CreateVoucherAsync error: {ex.Message}");
            }

            if (!createVoucherServiceResult.Success)
            {
                Debug.WriteLine($"++++ CreateVoucherAsync result error: {createVoucherServiceResult.FailureReason}");
                foreach (var response in createVoucherServiceResult.Log)
                {
                    Debug.WriteLine($"  ++ service operation: {response.RequestMessage.RequestUri} , result: {response.StatusCode}");
                }
            }

            return createVoucherServiceResult;
        }

        public async Task<ServiceResult<AnnullaVoucherBean>> DeleteVoucherAsync(Cookie fedSecureToken, Voucher voucher)
        {
            String serviceEndpoint = Settings.IsProductionEnvironment ? Constants.SERVICE_ENDPOINT_ProdEnv : Constants.SERVICE_ENDPOINT_TestEnv;
            httpClient = HttpClientFactory.Builder(ClientId, ClientSecret, fedSecureToken);
            var deleteVoucherServiceResult = new ServiceResult<AnnullaVoucherBean>();

            try
            {
                // Cancello il voucher
                var ambito = (voucher?.Shop?.IsOnline ?? false) ? "annullaVoucherOnline" : "annullaVoucherFisico";
                var response = await httpClient.GetAsync($"{serviceEndpoint}/BONUSWS/rest/secured/gestioneVoucher/{ambito}/{voucher.Id}");
                await deleteVoucherServiceResult.ProcessAsync(response);
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"++++ DeleteVoucherAsync error: {ex.Message}");
            }

            if (!deleteVoucherServiceResult.Success)
            {
                Debug.WriteLine($"++++ DeleteVoucherAsync result error: {deleteVoucherServiceResult.FailureReason}");
                foreach (var response in deleteVoucherServiceResult.Log)
                {
                    Debug.WriteLine($"  ++ service operation: {response.RequestMessage.RequestUri} , result: {response.StatusCode}");
                }
            }

            return deleteVoucherServiceResult;
        }

        #region Utils

        public AmbitoBean AmbitoBeanFromCategoria(Categoria categoria)
        {
            return new AmbitoBean
            {
                IdAmbito = categoria?.Id ?? null
            };
        }

        private BeneBean BeneBeanFromProdotto(Prodotto prodotto)
        {
            return new BeneBean
            {
                IdBene = prodotto?.Id ?? null
            };
        }

        #endregion
    }
}
