const { chromium } = require('playwright');
const Sentiment  = require('sentiment');
const ExcelJS    = require('exceljs');
const fs         = require('fs');
const path       = require('path');
const { POSITIVE_ID, NEGATIVE_ID } = require('../words_id');

const analyzer = new Sentiment();
analyzer.registerLanguage('id', {
  labels: { ...POSITIVE_ID, ...NEGATIVE_ID },
});

function analyzeSentiment(text) {
  const idResult = analyzer.analyze(text, { language: 'id' });
  const enResult = analyzer.analyze(text);
  const combinedScore = (idResult.score * 0.6) + (enResult.score * 0.4);
  const comparative = combinedScore / Math.max(text.split(/\s+/).length, 1);

  let label;
  if (combinedScore > 0.5) label = 'POSITIF';
  else if (combinedScore < -0.5) label = 'NEGATIF';
  else label = 'NETRAL';

  return {
    score: parseFloat(combinedScore.toFixed(2)),
    label,
    comparative: parseFloat(comparative.toFixed(4)),
    words_pos: idResult.positive.concat(enResult.positive).join(' | '),
    words_neg: idResult.negative.concat(enResult.negative).join(' | '),
  };
}

async function saveXLSX(records, filePath) {
  if (!records.length) return false;

  const workbook  = new ExcelJS.Workbook();
  workbook.creator = 'botScraping';
  workbook.created = new Date();
  const sheet = workbook.addWorksheet('Hasil Sentimen', { views: [{ state: 'frozen', ySplit: 1 }] });

  sheet.columns = [
    { key: 'user', header: 'User', width: 22 },
    { key: 'teks', header: 'Teks Tweet', width: 60 },
    { key: 'tautan', header: 'Tautan', width: 45 },
    { key: 'like', header: 'Like', width: 8 },
    { key: 'retweet', header: 'Retweet', width: 10 },
    { key: 'reply', header: 'Reply', width: 8 },
    { key: 'sentimen', header: 'Sentimen', width: 12 },
    { key: 'skor_sentimen', header: 'Skor', width: 8 },
    { key: 'comparative', header: 'Comparative', width: 13 },
    { key: 'kata_positif', header: 'Kata Positif', width: 30 },
    { key: 'kata_negatif', header: 'Kata Negatif', width: 30 },
    { key: 'keyword', header: 'Keyword', width: 14 },
    { key: 'scraped_at', header: 'Scraped At', width: 22 },
  ];

  const headerRow = sheet.getRow(1);
  headerRow.eachCell(cell => {
    cell.font = { bold: true, color: { argb: 'FFFFFFFF' }, size: 11 };
    cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF1F4E79' } };
    cell.alignment = { vertical: 'middle', horizontal: 'center' };
  });

  const COLORS = {
    POSITIF: { bg: 'FFE2EFDA', fg: 'FF375623' },
    NEGATIF: { bg: 'FFFCE4D6', fg: 'FF833C00' },
    NETRAL: { bg: 'FFF2F2F2', fg: 'FF595959' },
  };

  records.forEach((record, idx) => {
    const row = sheet.addRow(record);
    const sentVal = (record.sentimen || 'NETRAL').toUpperCase();
    const color = COLORS[sentVal] || COLORS.NETRAL;
    const isEven = idx % 2 === 1;

    row.eachCell({ includeEmpty: true }, (cell, colNumber) => {
      if (colNumber === 7) {
        cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: color.bg } };
        cell.font = { bold: true, color: { argb: color.fg } };
        cell.alignment = { horizontal: 'center', vertical: 'top' };
      } else {
        if (isEven) cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF7FBFF' } };
        cell.alignment = { vertical: 'top', wrapText: colNumber === 2 };
      }
    });
    const lines = Math.ceil((record.teks || '').length / 80);
    row.height = Math.min(Math.max(lines * 15, 18), 80);
  });

  await workbook.xlsx.writeFile(filePath);
  return true;
}

async function runScraperWeb(keyword, maxTweets, authToken, userId, since, until) {
  const browser = await chromium.launch({ headless: true });
  const context = await browser.newContext({
    userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
    locale: 'id-ID',
    viewport: { width: 1280, height: 900 },
  });

  await context.addCookies([
    { name: 'auth_token', value: authToken, domain: '.x.com', path: '/' },
  ]);

  const page = await context.newPage();
  let rawTweets = [];

  try {
    let finalKeyword = keyword;
    if (since) finalKeyword += ` since:${since}`;
    if (until) finalKeyword += ` until:${until}`;
    
    const searchUrl = `https://x.com/search?q=${encodeURIComponent(finalKeyword)}&src=typed_query&f=live`;
    await page.goto(searchUrl, { waitUntil: 'domcontentloaded', timeout: 30000 });
    await page.waitForSelector('article[data-testid="tweet"]', { timeout: 20000 });

    const seen = new Set();
    let previousCount = 0;
    let noNewTweetsCount = 0;
    let s = 0;
    const MAX_SCROLL_ATTEMPTS = Math.max(30, Math.ceil(maxTweets / 2));

    while (rawTweets.length < maxTweets && s < MAX_SCROLL_ATTEMPTS) {
      const batch = await page.evaluate(() => {
        const articles = document.querySelectorAll('article[data-testid="tweet"]');
        const result = [];
        articles.forEach(item => {
          const teksEl = item.querySelector('[data-testid="tweetText"]');
          const teks = teksEl ? teksEl.innerText.trim() : '';
          const timeEl = item.querySelector('time');
          const href = (timeEl && timeEl.parentElement) ? timeEl.parentElement.href : '';
          const likeEl = item.querySelector('[data-testid="like"] span');
          const like = likeEl ? likeEl.innerText.trim() : '0';
          const rtEl = item.querySelector('[data-testid="retweet"] span');
          const rt = rtEl ? rtEl.innerText.trim() : '0';
          const replyEl = item.querySelector('[data-testid="reply"] span');
          const reply = replyEl ? replyEl.innerText.trim() : '0';
          const userEl = item.querySelector('[data-testid="User-Name"]');
          const user = userEl ? userEl.innerText.split('\n')[0].trim() : 'Unknown';

          if (teks) result.push({ teks, tautan: href, like, retweet: rt, reply, user });
        });
        return result;
      });

      for (const t of batch) {
        if (!seen.has(t.tautan) && rawTweets.length < maxTweets) {
          seen.add(t.tautan);
          rawTweets.push(t);
        }
      }

      s++;
      if (rawTweets.length === previousCount) {
        noNewTweetsCount++;
        if (noNewTweetsCount >= 4) break;
      } else {
        noNewTweetsCount = 0;
      }
      previousCount = rawTweets.length;

      await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
      await page.waitForTimeout(3000 + Math.random() * 1500);
    }
  } catch (err) {
    console.error('Scraping error:', err.message);
    throw err;
  } finally {
    await browser.close();
  }

  if (rawTweets.length === 0) return null;

  const now = new Date().toLocaleString('id-ID', { timeZone: 'Asia/Jakarta' });
  const records = rawTweets.map(t => {
    const s = analyzeSentiment(t.teks);
    return { ...t, sentimen: s.label, skor_sentimen: s.score, comparative: s.comparative, kata_positif: s.words_pos, kata_negatif: s.words_neg, keyword, scraped_at: now };
  });

  const pos = records.filter(r => r.sentimen === 'POSITIF').length;
  const neg = records.filter(r => r.sentimen === 'NEGATIF').length;
  const neu = records.filter(r => r.sentimen === 'NETRAL').length;
  const total = records.length;

  const pct = (n) => ((n / total) * 100).toFixed(1) + '%';
  
  const timestamp = Date.now();
  const filename = `sentimen_${userId}_${timestamp}.xlsx`;
  const filePath = path.join(__dirname, '../public', filename);

  await saveXLSX(records, filePath);

  return {
    filename,
    stats: {
      total,
      pos, neg, neu,
      pctPos: pct(pos), pctNeg: pct(neg), pctNeu: pct(neu)
    },
    preview: records.slice(0, 5)
  };
}

module.exports = { runScraperWeb };
