import { JSDOM } from 'jsdom';
import libxmljs, { parseXmlAsync } from 'libxmljs';
import * as fs from 'node:fs';

const BASE_URL = process.env.BASE_URL ? process.env.BASE_URL: 'https://www.ecologie.gouv.fr';
//const fs = require('fs')


export async function getActuFile(actus) {
  const path_file = '../target/actu.json';
  fs.writeFile(path_file, JSON.stringify(actus), (err) => {
    if (err) throw err;
  })
  return path_file;
}
/**
 * Get Actualités links
 * @param {*} nbActu
 */
export async function getActu(nbActu) {
let index = 0;
  const urls = [];
  while (true) {
    if (nbActu - urls.length <= 0) {
      break;
    }
    const newUrls = await getArticles({
      xpathNode: '//article[@role="article"]',
      xpathUrl: 'string(descendant::h2/a/@href)',
      xpathTitle: 'string(descendant::h2/a/span/text())',
      xpathDate:
        'string(descendant::span[@class="entity-date"]/text())',
      url: `${BASE_URL}/actualites?page=${index}`,
      nb: nbActu - urls.length,
      dateParser: (input) => {
        const frenchToEnglish = {
          'janvier': 'January',
          'février': 'February',
          'mars': 'March',
          'avril': 'April',
          'mai': 'May',
          'juin': 'June',
          'juillet': 'July',
          'août': 'August',
          'septembre': 'September',
          'octobre': 'October',
          'novembre': 'November',
          'décembre': 'December',
        };

        const parts = input.split(' ');
        parts[1] = frenchToEnglish[parts[1].toLowerCase()];
        const englishDate = parts.join(' ');

        const dateObj = new Date(Date.parse(englishDate));
        const day = dateObj.getDate().toString().padStart(2, '0');
        const month = (dateObj.getMonth() + 1).toString().padStart(2, '0');
        const year = dateObj.getFullYear();

        return `${day}/${month}/${year}`;
      },

    });
    if (newUrls.length === 0) {
      break;
    }
    urls.push(
      ...newUrls.slice(0, Math.min(nbActu - urls.length, newUrls.length)));
    index++;
    await new Promise((resolve) => setTimeout(resolve, 200));
  }
  return urls;
}

export async function getRdvFile(rdvs) {
  const path_file = '../target/rdv.json'
  fs.writeFile(path_file, JSON.stringify(rdvs), (err) => {
    if (err) throw err;
  })
  return path_file;
}

/**
 * Get Rendez-vous links
 * @param {*} nbLinks
 */
export async function getRendezvous(nbLinks) {
  return await getArticles({
    xpathNode:
      '//div[@class="taxonomy-term vocabulary-project-eco-edition rdv-list"]',
    xpathTitle: 'string(descendant::h3/a/text())',
    xpathUrl: 'string(descendant::h3/a/@href)',
    xpathDate:
      'string(descendant::div[contains(@class,"rdv-list-dates-first")])',
    dateParser: (input) => {
      const regex = /\s+/g;
      const cleanedString = input.replace(regex, ' ').trim();
      return cleanedString.replace(/(\d{2}) (\d{2}) (\d{4})/, '$1/$2/$3');
    },
    url: `${BASE_URL}/rendez-vous`,
    nb: nbLinks,
  });
}

export async function getPolPublicFile(pols) {
  let n = 1;
  const limit = 250;
  const uniquePols = [...new Map(pols.map(pol => [pol.url, pol])).values()]
  for (let i = 0; i < uniquePols.length; i += limit) {
    let pol = uniquePols.slice(i, (i + limit));
    fs.writeFile(`../target/polp${n}.json`, JSON.stringify(pol), (err) => {
      if (err) throw err;
    });
    n++;
  }
  return true;
}
export async function getPolPublics(nb) {
  let temp_urls = [];
  const all_urls = [];
  const url_polpubl = `${BASE_URL}/sitemap.xml?page=6`;
  const response = await fetch(url_polpubl);
  const data = await response.text();
  const parser = libxmljs.parseXml(data);
  const obj_urls = parser.find("//*[contains(@href, '/politiques/')]");
  for (let link = 0; link < obj_urls.length; link++) {
    temp_urls.push(obj_urls[link].getAttribute('href').value());
  }
  const urls = [...new Set(temp_urls)];
  for (let i = 0; i < urls.length; i++) {
    const newUrls = await getArticles({
      xpathNode:
      '//ul/li[@class="node "]',
      xpathTitle:
        'string(descendant::a/text())',
      xpathUrl: 'string(descendant::a/@href)',
      xpathDate:
        'string(descendant::article/p/text())',
      url: urls[i],
      nb: nb,
    });
    all_urls.push(
      ...newUrls.slice(0, Math.min(nb - all_urls.length, newUrls.length)));
    await new Promise((resolve) => setTimeout(resolve, 200));
  }
  return all_urls;
}

export async function getDossiersPresseFile(dossiers) {
  const path_file = '../target/dossiers_presse.json';
  fs.writeFile(path_file, JSON.stringify(dossiers), (err) => {
    if (err) throw err;
  })
  return path_file;
}

export async function getDossiersPresse(nb) {
  let index = 0;
  let urls = [];
  while (true) {
    if (nb - urls.length <= 0) {
      break;
    }
    const newUrls = await getArticles({
      xpathNode: '//article[@role="article"]',
      xpathUrl: 'string(descendant::h2/a/@href)',
      xpathTitle: 'string(descendant::h2/a/span/text())',
      xpathDate:
        'string(descendant::span[@class="entity-date"]/text())',
      url: `${BASE_URL}/presse?f[0]=type_presse%3A189&page=${index}`,
      nb: nb - urls.length,
      dateParser: (input) => {
        const frenchToEnglish = {
          'janvier': 'January',
          'février': 'February',
          'mars': 'March',
          'avril': 'April',
          'mai': 'May',
          'juin': 'June',
          'juillet': 'July',
          'août': 'August',
          'septembre': 'September',
          'octobre': 'October',
          'novembre': 'November',
          'décembre': 'December',
        };

        const parts = input.split(' ');
        parts[1] = frenchToEnglish[parts[1].toLowerCase()];
        const englishDate = parts.join(' ');

        const dateObj = new Date(Date.parse(englishDate));
        const day = dateObj.getDate().toString().padStart(2, '0');
        const month = (dateObj.getMonth() + 1).toString().padStart(2, '0');
        const year = dateObj.getFullYear();

        return `${day}/${month}/${year}`;
      },
    });
    if (newUrls.length === 0) {
      break;
    }
    urls.push(
      ...newUrls.slice(0, Math.min(nb- urls.length, newUrls.length)));
    index++;
    await new Promise((resolve) => setTimeout(resolve, 200));
  }
  return urls;
}

/**
 * Generic function to get links
 * @param {*} param0
 */
async function getArticles({
  xpathNode,
  xpathUrl,
  xpathTitle,
  xpathDate,
  dateParser,
  url,
  nb,
}) {
  const cpt_timeout = 3;
  let cpt = 0;
  const urls = [];
  if (nb <= 0) {
    return urls;
  }
  while (true) {
    try {
      console.error(`Fetching ${url} ...`);
      const response = await fetch(url);
      const data = await response.text();
    
      const dom = new JSDOM(data);
      const document = dom.window.document;
    
      const xpathResult = document.evaluate(
        xpathNode,
        document,
        null,
        dom.window.XPathResult.ORDERED_NODE_ITERATOR_TYPE,
        null,
      );
    
      let node = xpathResult.iterateNext();
      while (node) {
        let date = document.evaluate(
          xpathDate,
          node,
          null,
          dom.window.XPathResult.STRING_TYPE,
          null,
        ).stringValue;
        if (dateParser) {
          date = dateParser(date);
        }
        urls.push({
          url: toAbsoluteUrl(
            document.evaluate(
              xpathUrl,
              node,
              null,
              dom.window.XPathResult.STRING_TYPE,
              null,
            ).stringValue,
          ),
          title: document.evaluate(
            xpathTitle,
            node,
            null,
            dom.window.XPathResult.STRING_TYPE,
            null,
          ).stringValue,
          date,
        });
        if (urls.length === nb) {
          return urls;
        }
        node = xpathResult.iterateNext();
      }
      return urls;
    } 
    catch(error) {
      if (cpt < cpt_timeout) {
        cpt += 1;
        continue;
      }
      else {
        throw new Error("Timeout Error: Navigation Timeout");
        break;
      }
    }
  }
}

/**
 * Convert captured URL into absolute URL
 * @param {*} value
 * @return {*}
 */
function toAbsoluteUrl(value) {
  if (value.startsWith('http')) {
    return value;
  } else if (value.startsWith('/')) {
    return `${BASE_URL}${value}`;
  } else {
    return `${BASE_URL}/${value}`;
  }
}
