const fs = require("fs").promises;
const path = require("path");
const process = require("process");
const { google } = require("googleapis");
const { OAuth2Client } = require("google-auth-library");
const http = require("http");
const url = require("url");

// const destroyer = require('server-destroy');

const CON = require("./const");

const TOKEN_PATH = path.join(process.cwd(), "content/token.json");
const CREDENTIALS_PATH = path.join(
  process.cwd(),
  "content/client_secret_926212607479-d3m8hm8f8esp3rf1639prskn445sa01v.apps.googleusercontent.com.json"
);

//generates iCalendar file for a single shift
const GenerateICS = function (shifts) {
  // https://stackoverflow.com/questions/3665115/create-a-file-in-memory-for-user-to-download-not-through-server

  var content = "BEGIN:VCALENDAR\n";
  content += "VERSION:2.0\n";
  content += "PRODID:-//JW Cart//Shift Info//EN\n";
  content += "CALSCALE:GREGORIAN\n";
  content += "METHOD:PUBLISH\n";
  content += "X-WR-CALNAME:Колички София-Изток\n";
  content += "X-WR-TIMEZONE:Europe/Sofia\n";
  content += "BEGIN:VTIMEZONE\n";
  content += "TZID:Europe/Sofia\n";
  content += "BEGIN:DAYLIGHT\n";
  content += "TZOFFSETFROM:+0200\n";
  content += "TZOFFSETTO:+0300\n";
  content += "TZNAME:EEST\n";
  content += "DTSTART:19700329T020000\n";
  content += "RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\n";
  content += "END:DAYLIGHT\n";
  content += "BEGIN:STANDARD\n";
  content += "TZOFFSETFROM:+0300\n";
  content += "TZOFFSETTO:+0200\n";
  content += "TZNAME:EET\n";
  content += "DTSTART:19701025T030000\n";
  content += "RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\n";
  content += "END:STANDARD\n";
  content += "END:VTIMEZONE\n";
  content += shifts?.map((shift) => {
    var content = "BEGIN:VEVENT\n";
    content += "DTSTAMP:" + new Date().getTime() + "\n";
    content += "UID:" + shift.id + "\n";
    content +=
      "DTSTART;TZID=Europe/Sofia:" +
      CON.GetDateTimeShort(shift.startTime) +
      "\n";
    content +=
      "DTEND;TZID=Europe/Sofia:" +
      CON.GetDateTimeShort(shift.endTime.getTime()) +
      "\n";
    content += "LOCATION:" + shift.cartEvent.location.name + "\n";
    //   content += "SUMMARY:" + shift.cartEvent.location.name + "\n";

    // Adding a VALARM component for a reminder 1 day before the event
    content += "BEGIN:VALARM\n";
    content += "TRIGGER:-P1D\n"; // Trigger alarm 1 day before the event
    content += "ACTION:DISPLAY\n";
    content += "DESCRIPTION:Reminder\n";
    content += "END:VALARM\n";
    content += "END:VEVENT";
    return content;
  })
    .join("\n");

  content += "END:VCALENDAR\n";
  //encode content in base64 to be send as attachment
  return Buffer.from(content).toString("base64");
};

// /**
//  * Reads previously authorized credentials from the save file.
//  *
//  * @return {Promise<OAuth2Client|null>}
//  */
// loadSavedCredentialsIfExist = async function loadSavedCredentialsIfExist() {
//     try {
//         const content = await fs.readFile(TOKEN_PATH);
//         const credentials = JSON.parse(content);
//         return google.auth.fromJSON(credentials);
//     } catch (err) {
//         return null;
//     }
// }

// /**
//  * Serializes credentials to a file compatible with GoogleAUth.fromJSON.
//  *
//  * @param {OAuth2Client} client
//  * @return {Promise<void>}
//  */
// saveCredentials = async function saveCredentials(client) {
//     const content = await fs.readFile(CREDENTIALS_PATH);
//     const keys = JSON.parse(content);
//     const key = keys.installed || keys.web;
//     const payload = JSON.stringify({
//         type: 'authorized_user',
//         client_id: key.client_id,
//         client_secret: key.client_secret,
//         refresh_token: client.credentials.refresh_token,
//     });
//     await fs.writeFile(TOKEN_PATH, payload);
// }

// /**
//  * Load or request or authorization to call APIs.
//  *
//  */
// authorize = async function authorize() {
//     let client = await exports.loadSavedCredentialsIfExist();
//     if (client) {
//         return client;
//     }
//     client = await exports.authenticate({
//         scopes: SCOPES,
//         keyfilePath: CREDENTIALS_PATH,
//     });
//     if (client.credentials) {
//         await saveCredentials(client);
//     }
//     return client;
// }

// /**
//  * Lists the next 10 events on the user's primary calendar.
//  * @param {google.auth.OAuth2} auth An authorized OAuth2 client.
//  */
// listEvents = async function listEvents(auth) {
//     const calendar = google.calendar({ version: 'v3', auth });
//     const res = await calendar.events.list({
//         calendarId: 'primary',
//         timeMin: new Date().toISOString(),
//         maxResults: 10,
//         singleEvents: true,
//         orderBy: 'startTime',
//     });
//     const events = res.data.items;
//     if (!events || events.length === 0) {
//         console.log('No upcoming events found.');
//         return;
//     }
//     console.log('Upcoming 10 events:');
//     events.map((event, i) => {
//         const start = event.start.dateTime || event.start.date;
//         console.log(`${start} - ${event.summary}`);
//     });
// }
// //usage
// GetEvents = async function GetEvents(dateTime = new Date()) {
//     var events = exports.authorize().then(exports.listEvents).catch(console.error);
// }

// // const calendar = google.calendar({ version: 'v3', auth });

// const eventTest = {
//     summary: 'Test Event',
//     start: {
//         dateTime: '2023-01-01T09:00:00-07:00',
//         timeZone: 'Europe/Sofia',
//     },
//     end: {
//         dateTime: '2023-01-01T17:00:00-07:00',
//         timeZone: 'Europe/Sofia',
//     },
// };

// const TOKEN_PATH = path.join(process.cwd(), 'content/token.json');
// const CREDENTIALS_PATH = path.join(process.cwd(), 'content/client_secret_926212607479-d3m8hm8f8esp3rf1639prskn445sa01v.apps.googleusercontent.com.json');

// const createEvent = async function createEvent(id) {
//   //     var eventTest2 = {
//   //         'summary': 'Google I/O 2015',
//   //         'location': '800 Howard St., San Francisco, CA 94103',
//   //         'description': 'A chance to hear more about Google\'s developer products.',
//   //         'start': {
//   //             'dateTime': '2015-05-28T09:00:00-07:00',
//   //             'timeZone': 'America/Los_Angeles',
//   //         },
//   //         'end': {
//   //             'dateTime': '2015-05-28T17:00:00-07:00',
//   //             'timeZone': 'America/Los_Angeles',
//   //         },
//   //         'recurrence': [
//   //             'RRULE:FREQ=DAILY;COUNT=2'
//   //         ],
//   //         'attendees': [
//   //             { 'email': '' },

//   //         ],
//   //         'reminders': {
//   //             'useDefault': false,
//   //             'overrides': [
//   //                 { 'method': 'email', 'minutes': 24 * 60 },
//   //                 { 'method': 'popup', 'minutes': 10 },
//   //             ],
//   //         },
//   //     };
//   //     var errors;
//   //     var auth = await exports.authorize().then((auth) => {

//   //         const calendar = google.calendar({ version: 'v3', auth });
//   //         const res = calendar.events.insert({
//   //             calendarId: 'primary',
//   //             resource: eventTest,

//   //         }, (err, event) => {
//   //             if (err) {
//   //                 console.log(`There was an error creating the event: ${err}`);
//   //                 return;
//   //             }
//   //             console.log(`Event created: ${event.data.htmlLink}`);
//   //         });
//   //     }).catch(console.error).then((err) => {
//   //         errors = err;
//   //     });
//   //     return errors;
//   // }

//   // authorizeNew = async function authorizeNew() {
//   //     let client = await loadSavedCredentialsIfExist();
//   //     if (client) {
//   //         return client;
//   //     }
//   // // Set up the Google Calendar API client
//   // const calendar = google.calendar({ version: 'v3', auth });

//   // // Load the client secrets from a JSON file

//   fs.readFile("./path/to/client_secret.json", (err, content) => {
//     if (err) return console.error("Error loading client secret file:", err);

//     // Authorize a client with the loaded credentials
//     authorizeOA(JSON.parse(content), calendar.calendarList.list);
//   });
//   if (client.credentials) {
//     await saveCredentials(client);
//   }
//   return client;
// };

// var googletoken = axiosInstance.get("/content/google_token.json");
// console.log("googletoken: " + googletoken);
// if (!googletoken) {
//     toast.error("Google token not found. redirecting to google login");
//     const { data, error } = axiosInstance.get('/content/client_secret_926212607479-d3m8hm8f8esp3rf1639prskn445sa01v.apps.googleusercontent.com.json',
//         { headers: { 'Content-Type': 'application/json' } });
//     console.log("data: " + JSON.stringify(data));
//     console.log("error: " + JSON.stringify(error));
//     var secrets = data;
//     const { google } = await import('googleapis');
//     const { OAuth2 } = google.auth;
//     const oAuth2Client = new OAuth2(
//         secrets.web.client_id,
//         secrets.web.client_secret,
//         secrets.web.redirect_uris[0]
//     );
//     const authorizationUrl = oauth2Client.generateAuthUrl({
//         // 'online' (default) or 'offline' (gets refresh_token)
//         access_type: 'offline',
//         /** Pass in the scopes array defined above.
//           * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
//         scope: scopes,
//         // Enable incremental authorization. Recommended as a best practice.
//         include_granted_scopes: true
//     });
//     return { redirect: authorizationUrl };

/**
 * Create an OAuth2 client with the given credentials, and then execute the
 * given callback function.
 * @param {Object} credentials The authorization client credentials.
 * @param {function} callback The callback to call with the authorized client.
 */
function authorizeOA(credentials, callback) {
  const { client_secret, client_id, redirect_uris } =
    credentials.installed || credentials.web;
  const oAuth2Client = new OAuth2Client(
    client_id,
    client_secret,
    redirect_uris[0]
  );

  // Check if we have previously stored a token
  fs.readFile(TOKEN_PATH, (err, token) => {
    if (err) return getAccessToken(oAuth2Client, callback);
    oAuth2Client.setCredentials(JSON.parse(token));
    callback(oAuth2Client);
  });
}

/**
 * Get and store new token after prompting for user authorization, and then
 * execute the given callback with the authorized OAuth2 client.
 * @param {google.auth.OAuth2} oAuth2Client The OAuth2 client to get token for.
 * @param {getEventsCallback} callback The callback for the authorized client.
 */
function getAccessToken(oAuth2Client, callback) {
  const authUrl = oAuth2Client.generateAuthUrl({
    access_type: "offline",
    scope: ["https://www.googleapis.com/auth/calendar"],
  });
  console.log("Authorize this app by visiting this url:", authUrl);
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });
  rl.question("Enter the code from that page here: ", (code) => {
    rl.close();
    oAuth2Client.getToken(code, (err, token) => {
      if (err) return console.error("Error retrieving access token", err);
      oAuth2Client.setCredentials(token);
      // Store the token to disk for later program executions
      fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
        if (err) return console.error(err);
        console.log("Token stored to", TOKEN_PATH);
      });
      callback(oAuth2Client);
    });
  });
}

// // /**
// //  * Lists the next 10 events on the user's primary calendar.
// //  * @param {google.auth.OAuth2} auth An authorized OAuth2 client.
// //  * @param {getEventsCallback} callback The callback for the authorized client.
// //  *
// //  */
// // function listEvents(auth) {
// //     const calendar = google.calendar({ version: 'v3', auth });
// //     calendar.events.list({
// //         calendarId: 'primary',
// //         timeMin: (new Date()).toISOString(),
// //         maxResults: 10,
// //         singleEvents: true,
// //         orderBy: 'startTime',
// //     }, (err, res) => {
// //         if (err) return console.error('The API returned an error: ' + err);
// //         const events = res.data.items;
// //         if (events.length) {
// //         console.log('Upcoming 10 events:');
// //         events.map((event, i) => {
// //             const start = event.start.dateTime || event.start.date;
// //             console.log(`${start} - ${event.summary}`);
// //         });
// //         } else {
// //         console.log('No upcoming events found.');
// //         }
// //     });
// //     }
//     // [END calendar_quickstart]
//     module.exports = {
//         GenerateICS,
//         createEvent,
//         authorize,
//         TOKEN_PATH,
//         CREDENTIALS_PATH
//     }

async function importModules() {
  const openModule = await import('open');
  const getPortModule = await import('get-port');
  return {
    open: openModule.default,
    getPort: getPortModule.default
  };
}

const createEvent = async (event) => {

  const { open, getPort } = await importModules();

  event = event || {
    summary: "Test Event",
    location: "Online",
    start: {
      dateTime: "2022-12-19T09:00:00Z",
      timeZone: "UTC",
    },
    end: {
      dateTime: "2022-12-19T10:00:00Z",
      timeZone: "UTC",
    },
  };

  try {
    const fc = await fs.readFile(CREDENTIALS_PATH);
    // const auth = new google.auth.fromClientSecret(fc);

    const secrets = JSON.parse(fc);

    const { google } = await import("googleapis");
    const { OAuth2 } = google.auth;
    var callbackUrl = secrets.web.redirect_uris[0];
    const freePort = await getPort();
    const url = new URL(callbackUrl);
    url.port = freePort;
    callbackUrl = url.toString();
    const oAuth2Client = new OAuth2(
      secrets.web.client_id,
      secrets.web.client_secret,
      callbackUrl
    );
    // Generate the url that will be used for the consent dialog.
    const authorizeUrl = oAuth2Client.generateAuthUrl({
      access_type: "offline",
      scope: "https://www.googleapis.com/auth/userinfo.profile",
    });

    let doAuth = await new Promise((resolve, reject) => {
      const server = http
        .createServer(async (req, res) => {
          try {
            if (req.url.indexOf("/oauth2callback") > -1) {
              // acquire the code from the querystring, and close the web server.
              const qs = new url.URL(req.url, "http://localhost:3003")
                .searchParams;
              const code = qs.get("code");
              console.log(`Code is ${code}`);
              res.end(
                "Authentication successful! Please return to the console."
              );
              server.destroy();

              // Now that we have the code, use that to acquire tokens.
              const r = await oAuth2Client.getToken(code);
              // Make sure to set the credentials on the OAuth2 client.
              oAuth2Client.setCredentials(r.tokens);
              auth = oAuth2Client;
              console.info("Tokens acquired.");
              resolve(oAuth2Client);
            }
          } catch (e) {
            reject(e);
          }
        })
        .listen(3003, () => {
          // open the browser to the authorize url to start the workflow
          open(authorizeUrl, { wait: false }).then((cp) => cp.unref());
          console.log(
            "Server started for auth flow to complete: " + authorizeUrl
          );
        });
      // destroyer(server);
    });

    doAuth.then((auth) => {
      const calendar = google.calendar({ version: "v3", auth: auth });
      calendar.events.insert(
        {
          auth: auth,
          calendarId: "primary",
          resource: event,
        },
        function (err, event) {
          if (err) {
            console.log(
              "There was an error contacting the Calendar service: " + err
            );
            return;
          }
          console.log("Event created: %s", event.htmlLink);
        }
      );
    });
  } catch (err) {
    console.log(err);
  }
};

const SaveEventsInGoogleCalendar = async function SaveEventsInGoogleCalendar(events) {
  // Load client secrets from a local file.
  try {
    const content = await fs.readFile(CREDENTIALS_PATH);
    // Authorize a client with credentials, then call the Google Calendar API.
    authorize(JSON.parse(content), createEvent);


  } catch (err) {
    console.log("Error loading client secret file:", err);
  }
};



exports.GenerateICS = GenerateICS;
exports.createEvent = createEvent;
exports.SaveEventsInGoogleCalendar = SaveEventsInGoogleCalendar;


//createEvent();
