using System;
using System.Collections.Generic;
using System.Configuration;
using System.Threading.Tasks;
using Tessitura.Service;
using Tessitura.Service.Contract;
using Tessitura.Service.Facade;

namespace Tessitura
{
    internal class Program
    {
        private static TessituraServiceFacade tessituraService;

        private static void Main()
        {
            var t = MainAsync();
            t.Wait();
        }

        private static async Task MainAsync()
        {
            // Get some values from the config and create an instance of the service
            var baseUri = ConfigurationManager.AppSettings.Get("ApiBaseUri");
            var timeout = int.Parse(ConfigurationManager.AppSettings.Get("Timeout"));
            tessituraService = new TessituraServiceFacade(baseUri, timeout);

            // Add our auth header (This is obviously not how you would manage credentials, 
            // but for clarity we will just hardcode values here.)
            var userCredentials = new UserCredentials("admin", "allright", "machine", "password");
            tessituraService.SetCredentials(userCredentials);

            // That's it.  Let's make a call
            var priceTypesResponse = await tessituraService.Txn.PriceTypes.GetAll();
            if (priceTypesResponse.ErrorMessages != null)
            {
                ShowErrorsAndExit(priceTypesResponse.ErrorMessages);
                return;
            }
            Console.WriteLine("Pricetypes:");
            Console.WriteLine("----------------------------------------------");
            foreach (var priceType in priceTypesResponse.ResponseObject)
            {
                Console.WriteLine(priceType.Description);
            }
            Console.WriteLine();

            // That was a GET, how about a POST?
            // We will add an Alias, but first need to get some reference data
            var aliasTypesResponse = await tessituraService.Referencedata.AliasTypes.GetSummaries();
            if (aliasTypesResponse.ErrorMessages != null)
            {
                ShowErrorsAndExit(aliasTypesResponse.ErrorMessages);
                return;
            }

            // Now use that referenceData in our POST
            var aliasToCreate = new Alias
            {
                Constituent = new Entity {Id = 6},
                AliasFirstName = "Test",
                AliasLastName = "Alias Added " + new Random().Next(),
                AliasType = aliasTypesResponse.ResponseObject[0]
            };
            var createAliasResponse = await tessituraService.Crm.Aliases.Create(aliasToCreate);

            if (createAliasResponse.ErrorMessages != null)
            {
                ShowErrorsAndExit(createAliasResponse.ErrorMessages);
                return;
            }

            Console.WriteLine("Created Alias {0}", createAliasResponse.ResponseObject.Id);

            // Great, but how about a Batch call?
            // Batch calls are made through the BatchFacade class off the root of 
            // the tessituraServiceFacade.  Calling down any of the method paths from
            // there will not return the objects, but the correctly formatted batch request 
            // to be added to the call.  Once you have all the requests built, you can
            // simply call .Call() and the service will organize it all for you and send
            // the request. Every Batch call takes an additional parameter List<DependsOnRequest>.
            // This allows you to use data from earlier requests as inputs to subsequent 
            // requests.  If you don't have any data dependencies, just pass null.
            var dependsOnRequestValid = new List<DependsOnRequest>
            {
                new DependsOnRequest
                {
                    Id = 1,
                    IsUrlDependency = true,
                    SourcePath = "Id",
                    TargetPath = "constituentId"
                }
            };
            var batchResponse = await tessituraService.BatchFacade
                .With(tessituraService.BatchFacade.Crm.Constituents.Get("6"))
                .With(tessituraService.BatchFacade.Crm.Aliases.GetAll("", "", dependsOnRequestValid))
                .Call();

            if (batchResponse.BatchFailed)
            {
                ShowBatchErrorsAndExit(batchResponse.Responses);
                return;
            }

            // Consuming the batch response objects will require you to upCast 
            // to the desired type. 
            Console.WriteLine("Aliases for Constituent {0};", ((Constituent) batchResponse.Responses[0].ResponseObject).DisplayName);
            Console.WriteLine("----------------------------------------------");
            foreach (var alias in (Aliases) batchResponse.Responses[1].ResponseObject)
            {
                Console.WriteLine("{0} {1}", alias.AliasFirstName, alias.AliasLastName);
            }
            Console.WriteLine();

            // Finally, we should clean up our junk data, so how about a DELETE
            var ourAliasId = createAliasResponse.ResponseObject.Id;
            var deleteResponse = await tessituraService.Crm.Aliases.Delete(ourAliasId.ToString());
            if (deleteResponse.ErrorMessages != null)
            {
                ShowErrorsAndExit(deleteResponse.ErrorMessages);
            }
            Console.WriteLine("Press any key to continue.");
            Console.Read();
        }

        private static void ShowBatchErrorsAndExit(IEnumerable<Response> responses)
        {
            foreach (var response in responses)
            {
                foreach (var error in response.ErrorMessages)
                {
                    Console.WriteLine(error.Description);
                }
                Console.WriteLine();
            }
        }

        private static void ShowErrorsAndExit(ErrorMessages errorMessages)
        {
            //We have an issue
            foreach (var error in errorMessages)
            {
                Console.WriteLine(error.Description);
            }
        }
    }
}