package de.jeyp91.googlecalendar;

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.DateTime;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.calendar.CalendarScopes;
import com.google.api.services.calendar.Calendar;
import com.google.api.services.calendar.model.Event;
import com.google.api.services.calendar.model.EventDateTime;
import com.google.api.services.calendar.model.EventReminder;
import com.google.api.services.calendar.model.Events;
import de.jeyp91.tippliga.TLWLeague;
import de.jeyp91.tippliga.TLWMatchday;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class GoogleCalendarConnector {
    private static final String APPLICATION_NAME = "Google Calendar API Java Quickstart";
    private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
    private static final String TOKENS_DIRECTORY_PATH = "tokens";

    /**
     * Global instance of the scopes required by this quickstart.
     * If modifying these scopes, delete your previously saved tokens/ folder.
     */
    private static final List<String> SCOPES = Collections.singletonList(CalendarScopes.CALENDAR_READONLY);
    private static final String CREDENTIALS_FILE_PATH = "/Google_Credentials.json";

    /**
     * Creates an authorized Credential object.
     * @param HTTP_TRANSPORT The network HTTP Transport.
     * @return An authorized Credential object.
     * @throws IOException If the Google_Credentials.json file cannot be found.
     */
    private static Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT) throws IOException {
        // Load client secrets.
        InputStream in = GoogleCalendarConnector.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
        if (in == null) {
            throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH);
        }
        GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));

        // Build flow and trigger user authorization request.
        GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
                HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
                .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
                .setAccessType("offline")
                .build();
        LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8888).build();
        return new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
    }

    private static com.google.api.services.calendar.Calendar getSerivce() {

        com.google.api.services.calendar.Calendar service = null;

        final NetHttpTransport HTTP_TRANSPORT;
        try {
            HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
            service = new com.google.api.services.calendar.Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT))
                    .setApplicationName(APPLICATION_NAME)
                    .build();


        } catch (GeneralSecurityException | IOException e) {
            e.printStackTrace();
        }
        return service;
    }

    public static List<Event> getAllEventsStartingFromDateTime(int league, DateTime dateTime) {

        com.google.api.services.calendar.Calendar service = getSerivce();
        Events events = null;

        String calendarUrl = CalendarConfigProvider.getCalendarUrl(league);

        // Build a new authorized API client service.
        try {
            events = service.events().list(calendarUrl)
                    .setMaxResults(100)
                    .setTimeMin(dateTime)
                    .setOrderBy("startTime")
                    .setSingleEvents(true)
                    .execute();

        } catch (IOException e) {
            e.printStackTrace();
        }

        // List the next 10 events from the primary calendar.
        assert events != null;
        List<Event> items = events.getItems();

        return items;
    }

    public static void createNewEvent(TLWMatchday matchday) {
        Calendar service = getSerivce();

        String calendarId = CalendarConfigProvider.getCalendarId(matchday.getLeague());

        String matchdayName = matchday.getMatchdayName() == "" ? matchday.getMatchday().toString() + ". Spieltag" : matchday.getMatchdayName();
        String summary = "Tippabgabeschluss " + TLWLeague.getLeagueNameCalendar(matchday.getLeague()) + " " + matchdayName;
        String description = "Tippabgabeschluss " + TLWLeague.getLeagueNameCalendar(matchday.getLeague()) + " " + matchdayName;

        Event event = new Event()
                .setSummary(summary)
                .setLocation("https://www.tippliga-wuerzburg.de/app.php/football/bet")
                .setDescription(description);

        DateTime deliveryDate = new DateTime(matchday.getDeliveryDate().replace(" ", "T"));
        EventDateTime date = new EventDateTime()
                .setDateTime(deliveryDate)
                .setTimeZone("Europe/Berlin");
        event.setStart(date);
        event.setEnd(date);

        // Set reminder to 12 hours before
        Event.Reminders reminders = new Event.Reminders();
        EventReminder[] reminderOverrides = new EventReminder[] {
            new EventReminder().setMethod("popup").setMinutes(12 * 60),
        };
        reminders.setOverrides(Arrays.asList(reminderOverrides));
        event.setReminders(reminders);

        try {
            service.events().insert(calendarId, event).execute();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void updateMatchdayDate(TLWMatchday matchday) {

    }

    public static Event getEventForMatchday(TLWMatchday matchday) {
        return null;
    }
}