using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Google.Apis.Calendar.v3;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Calendar.v3.Data;
using MercatorApi;

namespace MercatorGoogleCalendarClient
{
    public static class Class
    {
        public static bool InsertOrUpdateEvent(string jsonCredentialsFile, string calendarId, EventDescriptor descriptor, out string errorMessage)
        {
            var service = getCalendarService(jsonCredentialsFile, calendarId, out errorMessage);
            if (service == null)
                return false;

            if (!string.IsNullOrWhiteSpace(descriptor.Id) && !descriptor.IsIdValid())
            {
                errorMessage = "Ongelig ID ! (mag enkel en alleen cijfers en kleine letters bevatten - min. 5)";
                return false;
            }

            var eventEntry = new Event
            {
                Id = string.IsNullOrWhiteSpace(descriptor.Id) ? Api.NewId().Replace("-", "").ToLower() : descriptor.Id,
                Summary = descriptor.Summary,
                Description = descriptor.Description,
                Start = new EventDateTime { DateTime = descriptor.Start },
                End = new EventDateTime { DateTime = descriptor.End },
            };

            if (string.IsNullOrWhiteSpace(descriptor.Id)) //Dit is een evenement dat nog nooit in de Google-agenda is aangemaakt
            {
                descriptor.Id = eventEntry.Id; // renvoyer le nouvel ID à l'appelant
                try
                {
                    var insertRequest = service.Events.Insert(eventEntry, calendarId);
                    insertRequest.Execute();
                }
                catch (Exception ex)
                {
                    errorMessage = "Toevoegen aan Google-agenda : " + ex.Message + (ex.InnerException != null ? "\r\n" + ex.InnerException.Message : "");
                    return false;
                }
            }
            else // Afspraak dewelke normaal al bestaat in de Google-agenda
            {
                try
                {
                    var updateRequest = service.Events.Update(eventEntry, calendarId, descriptor.Id);
                    updateRequest.Execute();
                }
                catch (Exception ex) // on gère ici l'exception levée si l'event n'existe pas dans le calendrier Google -> on crée un nouvel event
                {
                    if (ex.Message.Contains("404"))
                    {
                        try
                        {
                            var insertRequest = service.Events.Insert(eventEntry, calendarId);
                            insertRequest.Execute();
                        }
                        catch (Exception ex2)
                        {
                            errorMessage = "Toevoegen aan de Google-agenda : " + ex2.Message + (ex2.InnerException != null ? "\r\n" + ex2.InnerException.Message : "");
                            return false;
                        }
                    }
                    else
                    {
                        errorMessage = "Update van de Google-agenda : " + ex.Message + (ex.InnerException != null ? "\r\n" + ex.InnerException.Message : "");
                        return false;
                    }
                }
            }
            return true;
        }

        public static EventDescriptor GetEvent(string jsonCredentialsFile, string calendarId, string eventId, out string errorMessage)
        {
            var service = getCalendarService(jsonCredentialsFile, calendarId, out errorMessage);
            if (service == null)
                return null;

            Event eventEntry;
            try
            {
                var getrequest = service.Events.Get(calendarId, eventId);
                eventEntry = getrequest.Execute();
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("404"))
                    return null; // we beheren de uitzondering die hier wordt opgeworpen als het evenement niet bestaat in de Google-agenda -> we maken een nieuw evenement.
                {

                errorMessage = "Selectie Google-agenda : " + ex.Message + (ex.InnerException != null ? "\r\n" + ex.InnerException.Message : "");
                return null;
            }

            return new EventDescriptor
            {
                Id = eventEntry.Id,
                Summary = eventEntry.Summary,
                Description = eventEntry.Description,
                Start = eventEntry.Start.DateTime ?? new DateTime(1900, 1, 1),
                End = eventEntry.End.DateTime ?? new DateTime(1900, 1, 1)
            };
        }

        private static CalendarService getCalendarService(string jsonCredentialsFile, string calendarId, out string errorMessage)
        {
            errorMessage = null;
            string jsonCredentialsContent = Api.FileToStr("<Other\\" + jsonCredentialsFile);
            if (string.IsNullOrEmpty(jsonCredentialsContent))
            {
                errorMessage = string.Format("Bestand niet gevonden \"<Other\\{0}\" !", jsonCredentialsFile);
                return null;
            }

            JsonCredentialParameters jsonCredentialParameters;
            try
            {
                jsonCredentialParameters = Google.Apis.Json.NewtonsoftJsonSerializer.Instance.Deserialize<JsonCredentialParameters>(jsonCredentialsContent);
            }
            catch (Exception ex)
            {
                errorMessage = $"Uitlezen van {jsonCredentialsFile} : " + ex.Message + (ex.InnerException != null ? "\r\n" + ex.InnerException.Message : "");
                return null;
            }
            ServiceAccountCredential serviceAccountCredential = new ServiceAccountCredential
            (
                new ServiceAccountCredential.Initializer(jsonCredentialParameters.ClientEmail)
                {
                    Scopes = new string[1] { CalendarService.Scope.Calendar },
                }.FromPrivateKey(jsonCredentialParameters.PrivateKey)
            );

            CalendarService calendarService;
            try
            {
                calendarService = new CalendarService(new BaseClientService.Initializer()
                {
                    HttpClientInitializer = serviceAccountCredential,
                    ApplicationName = "MercatorGoogleCalendarClient"
                });
            }
            catch (Exception ex)
            {
                errorMessage = "Aanmaken CalendarService Google : " + ex.Message + (ex.InnerException != null ? "\r\n" + ex.InnerException.Message : "");
                return null;
            }

            Calendar calendar;
            try
            {
                calendar = calendarService.Calendars.Get(calendarId).Execute();
            }
            catch (Exception ex)
            {
                errorMessage = $"Selectie Google-Agenda : " + ex.Message + (ex.InnerException != null ? "\r\n" + ex.InnerException.Message : "");
            }

            return calendarService;
        }
    }

    public class EventDescriptor
    {
        public string Id { get; set; }
        public string Summary { get; set; }
        public string Description { get; set; }
        public DateTime Start { get; set; }
        public DateTime End { get; set; }

        public bool IsIdValid()
        {
            if (Id == null)
                return false;
            else
                return System.Text.RegularExpressions.Regex.Match(Id, "^[a-z0-9]{5,1024}$").Success;
        }
    }
}