import fs from 'fs/promises';
import { createWriteStream, existsSync, mkdirSync } from 'fs';
import path from 'path';
import puppeteer from 'puppeteer-extra';
import StealthPlugin from 'puppeteer-extra-plugin-stealth';
import TurndownService from 'turndown';
import https from 'https';

puppeteer.use(StealthPlugin());

const turndownService = new TurndownService({
  headingStyle: 'atx',
  codeBlockStyle: 'fenced'
});

// Remove unnecessary elements from Medium articles
turndownService.addRule('remove_unwanted', {
  filter: ['script', 'noscript', 'style', 'button', 'svg'],
  replacement: () => ''
});

const IMAGES_DIR = path.join(process.cwd(), 'public', 'blog', 'images');
const CONTENT_DIR = path.join(process.cwd(), 'content', 'blog');

async function ensureDirs() {
  if (!existsSync(IMAGES_DIR)) {
    await fs.mkdir(IMAGES_DIR, { recursive: true });
  }
  if (!existsSync(CONTENT_DIR)) {
    await fs.mkdir(CONTENT_DIR, { recursive: true });
  }
}

async function downloadImage(url, filename) {
  const destPath = path.join(IMAGES_DIR, filename);
  return new Promise((resolve) => {
    https.get(url, (res) => {
      if (res.statusCode !== 200) {
        return resolve(url); 
      }
      const file = createWriteStream(destPath);
      res.pipe(file);
      file.on('finish', () => { 
        file.close(); 
        resolve(`/blog/images/${filename}`); 
      });
      file.on('error', () => { 
        resolve(url); 
      });
    }).on('error', () => { 
        resolve(url); 
    });
  });
}

function cleanSlug(str) {
  let decoded = decodeURIComponent(str);
  // Remove the medium id suffix at the end e.g. -b3719c7aaacd
  decoded = decoded.replace(/-[a-f0-9]{8,12}$/i, '');
  return decoded.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
}

async function main() {
  await ensureDirs();

  // Clear existing content/blog directory as requested by the user
  const existingFiles = await fs.readdir(CONTENT_DIR);
  for (const file of existingFiles) {
    if (file.endsWith('.md')) {
      await fs.unlink(path.join(CONTENT_DIR, file));
    }
  }

  const fileContent = await fs.readFile(path.join(process.cwd(), 'docs/mediumLinks.md'), 'utf8');
  const urls = fileContent.split('\n').map(l => l.trim()).filter(l => l.length > 0);

  console.log(`Processing ${urls.length} articles...`);

  const browser = await puppeteer.launch({ 
    headless: 'new',
    args: ['--no-sandbox', '--disable-setuid-sandbox']
  });
  
  const page = await browser.newPage();
  await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36');
  await page.setViewport({ width: 1366, height: 768 });

  for (let i = 0; i < urls.length; i++) {
    const url = urls[i];
    console.log(`[${i + 1}/${urls.length}] Fetching ${url}`);
    
    try {
      await page.goto(url, { waitUntil: 'networkidle2', timeout: 60000 });
      
      const pageTitle = await page.title();
      if (pageTitle.includes('Just a moment')) {
        console.log('  -> Waiting for Cloudflare...');
        await new Promise(r => setTimeout(r, 7000));
      }

      await page.evaluate(() => window.scrollBy(0, document.body.scrollHeight));
      await new Promise(r => setTimeout(r, 1000));

      const meta = await page.evaluate(() => {
        const title = document.querySelector('h1')?.innerText || document.querySelector('meta[property="og:title"]')?.content || 'Unknown Title';
        const rawExcerpt = document.querySelector('meta[name="description"]')?.content || '';
        const coverImage = document.querySelector('meta[property="og:image"]')?.content || '';
        const canonical = document.querySelector('link[rel="canonical"]')?.href || '';
        const dateRaw = document.querySelector('meta[property="article:published_time"]')?.content || new Date().toISOString();
        
        const readTimeText = document.body.innerText.match(/\d+\s*min\s*read/i);
        const readTime = readTimeText ? readTimeText[0] : '5 min read';

        // Attempting to just grab the article element, without the author and social toolbars
        // Medium usually surrounds the actual article content in section tags
        let htmlContext = '';
        const sections = Array.from(document.querySelectorAll('article section'));
        if(sections.length > 0) {
            sections.forEach(s => { htmlContext += s.innerHTML; });
        } else {
            htmlContext = document.querySelector('article')?.innerHTML || '';
        }

        return { title, rawExcerpt, coverImage, canonical, dateRaw, readTime, htmlContext };
      });

      if (!meta.htmlContext) {
        console.log(`  -> Failed to find article content! Skipping.`);
        continue;
      }

      // Convert HTML back to markdown
      let markdown = turndownService.turndown(meta.htmlContext);

      // Clean metadata
      const rawSlug = url.split('/').pop().split('?')[0];
      const slug = cleanSlug(rawSlug);
      
      const date = meta.dateRaw.split('T')[0];
      const category = "General"; // Defaulting as discussed
      // Safely escape quotes in title/excerpt
      const safeTitle = meta.title.replace(/"/g, '\\"');
      const safeExcerpt = meta.rawExcerpt.replace(/"/g, '\\"');

      // Setup frontmatter
      const coverImageDest = `${slug}-cover.jpg`;
      const localCoverImageUrl = await downloadImage(meta.coverImage, coverImageDest);

      let frontmatter = `---
title: "${safeTitle}"
category: "${category}"
date: "${date}"
readTime: "${meta.readTime}"
author: "Poyraz Avsever"
slug: "${slug}"
excerpt: "${safeExcerpt}"
coverImage: "${localCoverImageUrl}"
canonicalUrl: "${url}"
lang: "tr"
---

`;

      // Download content images
      const imgRegex = /!\[(.*?)\]\((https:\/\/(?:miro\.medium\.com|cdn-images-\d+\.medium\.com)[^)]+)\)/g;
      const promises = [];
      const imageMap = {};

      let match;
      let imgId = 1;
      while ((match = imgRegex.exec(markdown)) !== null) {
        const originalUrl = match[2];
        const filename = `${slug}-img-${imgId++}.jpg`;
        promises.push(
          downloadImage(originalUrl, filename).then(localPath => {
            imageMap[originalUrl] = localPath;
          })
        );
      }

      await Promise.all(promises);

      // Replace urls in markdown
      Object.keys(imageMap).forEach(orig => {
        markdown = markdown.split(orig).join(imageMap[orig]);
      });

      // Medium adds a lot of "Follow me on Medium" user-bars in markdown output. We can keep it but remove the generic leading user snippet
      
      // Cleanup UI noise
      markdown = markdown.replace(/\[\s*!\[Poyraz Avsever\].*?\]\(.*?\)\s*\[Poyraz Avsever\].*?\s*\d+ min read\s*·\s*[A-Z][a-z]+\s+\d+,\s+\d+/gs, '');
      markdown = markdown.replace(/\[\s*\]\(\/m\/signin\?.*?\)/gs, '');
      markdown = markdown.replace(/Press enter or click to view image in full size/g, '');
      markdown = markdown.replace(/## Get Poyraz Avsever’s stories in.*?Remember me for faster sign in/gs, '');
      markdown = markdown.replace(/\n{4,}/g, '\n\n\n');

      const finalMd = frontmatter + markdown;
      const mdPath = path.join(CONTENT_DIR, `${slug}.md`);
      
      await fs.writeFile(mdPath, finalMd, 'utf8');
      console.log(`  -> Saved and Cleaned to ${mdPath}`);

    } catch (err) {
      console.error(`  -> Error processing ${url}:`, err.message);
    }
  }

  await browser.close();
  console.log('All articles processed!');
}

main();
