const puppeteer = require('puppeteer-extra');
const pluginStealth = require('puppeteer-extra-plugin-stealth');
const fs = require('fs');
const dayjs = require('dayjs');

puppeteer.use(pluginStealth());

// Change default locale to Indonesia
require('dayjs/locale/id');
dayjs.locale('id');

// Saving to PDF only work for headless mode
const headless = true;

// E-mail account
const email = 'your-email@gmail.com';
const password = 'your-email-password';

// Base path where to save the PDF result
const resultBasePath = './';

// Data to be crawled
// We make this to make dynamic crawler
const survey = JSON.parse(fs.readFileSync('survey.json'));

// Store last update time
const timestampsFile = 'timestamps.json';

function getTimestamps() {
  return JSON.parse(fs.readFileSync(timestampsFile));
}

function setTimestamps(data) {
  try {
    fs.writeFileSync(timestampsFile, JSON.stringify(data));
  } catch (err) {
    console.log('Failed to write timestamps', err);
  }
}

function updateSurveyTimestamp(key, value) {
  let timestamps = getTimestamps();
  timestamps[key] = value;
  setTimestamps(timestamps);
}

(async () => {
  const browser = await puppeteer.launch({ 
    headless,
    args: [
      '--no-sandbox',
      '--disable-setuid-sandbox',
      '--disable-dev-shm-usage',
      '--disable-accelerated-2d-canvas',
      '--no-first-run',
      '--no-zygote',
      '--disable-gpu',
      // '--single-process', // <- this one doesn't works in Windows
    ],
   });

  console.log('App running...');
  const page = await browser.newPage();
  const pages = await browser.pages();

  // Close the new tab that chromium always opens first.
  pages[0].close();
  
  await page.setBypassCSP(true);

  await page.goto('https://accounts.google.com/signin/v2/identifier', { waitUntil: 'networkidle2' });

  // Wait for email input.
  await page.waitForSelector('#identifierId');
  
  await page.type('#identifierId', email);
  await page.waitForTimeout(1000);
  await page.keyboard.press('Enter');
  await page.waitForTimeout(1000);

  // Wait for password input
  await page.waitForSelector('input[type="checkbox"]');
  await page.evaluate(() => {
    document.querySelector('input[type="checkbox"]').parentElement.click();
  });
  await page.waitForTimeout(1000);
  await page.type('input[type="text"]', password);
  await page.waitForTimeout(1000);
  await page.keyboard.press('Enter');
  
  await page.waitForSelector('[role="banner"]');

  for (let itemIndex = 0; itemIndex < survey.summaries.length; itemIndex++) {
    const item = survey.summaries[itemIndex];
    const now = dayjs();
    const lastUpdate = now.format('dddd, D MMMM YYYY') + ' pukul ' + now.format('HH.mm');
    
    // Print the title
    console.log('Getting for: ' + item.title);

    await page.goto(item.url);

    // Wait until loading gone!
    await page.waitForSelector('.freebirdCommonViewLoadingindicatorLoadingIndicatorContainer', {
      hidden: true
    });
    
    // Try to wait 'file unavailable' dialog
    // It will be removed later
    try {
      await page.waitForSelector('.quantumWizDialogBackground.isOpen', {
        timeout: 5000 // 5 seconds
      });
    } catch (err) {
      // do nothing
    }

    const summariesTitleToRemove = item.ignores;
    
    // Remove unused elements
    await page.evaluate((summariesTitleToRemove, lastUpdate) => {
      // Remove file unavailable dialog if exists
      const fileUnavailableDialog = document.querySelector('.quantumWizDialogBackground.isOpen');
      if (fileUnavailableDialog) fileUnavailableDialog.remove();
      
      // Change body background
      document.body.style.backgroundColor = '#ffffff';
      
      // Remove publish button
      document.querySelector('a.exportButtonNestedLink').remove();
      
      // Remove FAB
      document.querySelector('.freebirdFormviewerViewNavigationHeaderButtonContainer').remove();
      
      // Change footer content for last update
      document.querySelector('.freebirdFormviewerViewFooterDisclaimer').innerHTML = 'Diperbarui pada: ' + lastUpdate;
      // Or you can just remove the footer
      // document.querySelector('.freebirdFormviewerViewFooterDisclaimer').remove();
      // document.querySelector('.freebirdFormviewerViewFooterImageContainer').remove();
      
      // Remove unused summary by title
      const elementsToRemove = document.querySelectorAll('.freebirdAnalyticsViewAnalyticsItem');
      for (let i = 0; i < elementsToRemove.length; i++) {
        let el = elementsToRemove[i];
        // Finding title
        const title = el.querySelector('.freebirdAnalyticsViewQuestionTitle');
        const headerTitle = el.querySelector('.freebirdAnalyticsViewSectionHeader');
        if (
          (title && summariesTitleToRemove.includes(title.innerText)) || 
          (headerTitle && summariesTitleToRemove.includes(headerTitle.innerText))
        ) {
          elementsToRemove[i].parentNode.removeChild(elementsToRemove[i]);
        }
      }
    }, summariesTitleToRemove, lastUpdate);

    // Save content to file 
    console.log('Saving result: ' + item.filename);

    // PDF only works when headless active
    if (headless) {
      await page.pdf({
        path: resultBasePath + item.filename,
        printBackground: true,
        format: 'A4',
        margin: {
          top: '2cm',
          bottom: '2cm',
          left: '1cm',
          right: '1cm'
        }
      });
    }
    
    // Save last update
    updateSurveyTimestamp(item.filename, lastUpdate);
  }
  
  console.log('✅ Operation completed, have a good day!');

  browser.close();
})();