import fetch from 'node-fetch';
import { load as cheerioLoad } from 'cheerio';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import dotenv from 'dotenv';
import https from 'https';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

dotenv.config({ path: path.join(__dirname, '.env') });

// Config
const REGION = (process.env.REGION || 'eu').trim().toLowerCase();
const REALM = (process.env.REALM || '').trim().toLowerCase();
const NAME = (process.env.NAME || '').trim().toLowerCase();
const LOCALE = (process.env.LOCALE || 'en_US').toLowerCase();
const OUT_JSON = process.env.OUT_JSON || path.join(__dirname, 'armory.out.json');

const LOCALE_TO_PATH = {
  'en_us': 'en-us',
  'en_gb': 'en-gb',
  'de_de': 'de-de',
  'fr_fr': 'fr-fr',
  'es_es': 'es-es',
  'es_mx': 'es-mx',
  'it_it': 'it-it',
  'pt_br': 'pt-br',
  'ru_ru': 'ru-ru',
  'ko_kr': 'ko-kr',
  'zh_tw': 'zh-tw',
  'zh_cn': 'zh-cn',
};

function localePathForRegion(region) {
  const l = LOCALE;
  if (l && !l.startsWith('en_') && LOCALE_TO_PATH[l]) return LOCALE_TO_PATH[l];
  if (region === 'eu') return 'en-gb';
  if (region === 'us') return 'en-us';
  return LOCALE_TO_PATH[l] || 'en-us';
}

let sharedAgent;
function getHttpsAgent() {
  if (sharedAgent) return sharedAgent;
  const insecure = (process.env.INSECURE_TLS || '').toLowerCase() === '1' || (process.env.INSECURE_TLS || '').toLowerCase() === 'true';
  const caPath = process.env.CA_CERT_PATH || process.env.NODE_EXTRA_CA_CERTS;
  if (insecure) { sharedAgent = new https.Agent({ rejectUnauthorized: false, keepAlive: true }); return sharedAgent; }
  if (caPath && fs.existsSync(caPath)) {
    try { const ca = fs.readFileSync(caPath, 'utf8'); sharedAgent = new https.Agent({ ca, keepAlive: true }); return sharedAgent; } catch {}
  }
  sharedAgent = new https.Agent({ keepAlive: true });
  return sharedAgent;
}

function acceptLanguageForUrl(u) {
  try {
    const url = new URL(u);
    const p = url.pathname.toLowerCase();
    if (p.includes('/en-gb/')) return 'en-GB,en;q=0.9';
    if (p.includes('/en-us/')) return 'en-US,en;q=0.9';
  } catch {}
  const l = (LOCALE || 'en_US').replace('_', '-');
  return l;
}

async function fetchHTML(url) {
  const res = await fetch(url, {
    headers: {
      'User-Agent': 'Mozilla/5.0 PvPScout/armory (+https://github.com/dominikreckziegel/PvPScout) polite-fetch',
      'Accept-Language': acceptLanguageForUrl(url),
      'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
      'Cache-Control': 'no-cache',
    },
    agent: getHttpsAgent(),
  });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return await res.text();
}

function normalizeRealmSlug(realm) {
  let s = String(realm || '').toLowerCase().trim();
  s = s.replace(/\s+/g, '-');
  s = s.replace(/'|’/g, '');
  return s;
}

function buildCharacterUrl(region, realm, name) {
  const localePath = localePathForRegion(region);
  const realmSlug = normalizeRealmSlug(realm);
  const charName = encodeURIComponent(String(name || '').toLowerCase());
  // Add /pvp for the PvP tab to ensure ratings are present
  return `https://worldofwarcraft.blizzard.com/${localePath}/character/${region}/${realmSlug}/${charName}/pvp`;
}

function deepVisit(obj, fn) {
  const seen = new Set();
  const stack = [obj];
  while (stack.length) {
    const cur = stack.pop();
    if (!cur || typeof cur !== 'object') continue;
    if (seen.has(cur)) continue; seen.add(cur);
    fn(cur);
    if (Array.isArray(cur)) { for (const it of cur) stack.push(it); }
    else { for (const k of Object.keys(cur)) stack.push(cur[k]); }
  }
}

const BRACKET_SYNONYMS = {
  '2v2': ['2v2', 'ARENA_2V2', 'ARENA_2v2', 'arena_2v2', 'ARENA2v2'],
  '3v3': ['3v3', 'ARENA_3V3', 'ARENA_3v3', 'arena_3v3', 'ARENA3v3'],
  'rbg': ['rbg', '10v10', 'BATTLEGROUNDS_10v10', 'RBG', 'BATTLEGROUND_10v10', 'battlegrounds'],
  'shuffle': ['shuffle', 'solo_shuffle', 'SOLO_SHUFFLE', 'RATED_SOLO_SHUFFLE'],
  'blitz': ['blitz', 'BATTLEGROUND_BLITZ', 'rated_battleground_blitz', 'RBG_BLITZ']
};

function matchBracketTag(v) {
  if (!v) return null;
  const s = String(v).toLowerCase();
  for (const [key, arr] of Object.entries(BRACKET_SYNONYMS)) {
    if (arr.some(x => s.includes(String(x).toLowerCase()))) return key;
  }
  return null;
}

function parseArmory(html) {
  const $ = cheerioLoad(html);
  const next = $('#__NEXT_DATA__').first();
  if (!next.length) return {};
  let data;
  try { data = JSON.parse(next.text()); } catch { return {}; }
  const out = { brackets: {}, bySpec: { shuffle: {}, blitz: {} } };

  // Strategy: walk the JSON and collect any objects that look like PvP bracket summaries.
  deepVisit(data, (node) => {
    // Simple form: { bracket: 'ARENA_2V2', rating: 1800, bestRating: 2000, ... }
    if (node && typeof node === 'object' && Number.isFinite(node.rating)) {
      const b = matchBracketTag(node.bracket || node.bracketId || node.type || node.slug || node.title || node.name);
      if (b) {
        out.brackets[b] = out.brackets[b] || {};
        if (Number.isFinite(node.rating)) out.brackets[b].rating = Math.max(out.brackets[b].rating || 0, Number(node.rating));
        if (Number.isFinite(node.rank)) out.brackets[b].rank = Number(node.rank);
      }
      // Spec ratings (appears in tooltips/tiles arrays)
      const spec = (node.specialization && (node.specialization.slug || node.specialization.name)) || node.spec || node.specSlug;
      const bb = matchBracketTag(node.parentBracket || node.parent || node.group || node.bracket || node.type);
      if (spec && bb && (bb === 'shuffle' || bb === 'blitz')) {
        const slug = String((spec.slug || spec) || '').toLowerCase().replace(/\s+/g, '-');
        if (slug) {
          out.bySpec[bb][slug] = { rating: Number(node.rating) || 0, rank: Number(node.rank) || 0 };
        }
      }
    }

    // Alternate arrays like { brackets: [{ id:'ARENA_2V2', rating: 1800}, ...] }
    if (node && typeof node === 'object' && Array.isArray(node.brackets)) {
      for (const it of node.brackets) {
        const b = matchBracketTag(it && (it.id || it.slug || it.type || it.name));
        if (b && Number.isFinite(it && it.rating)) {
          out.brackets[b] = out.brackets[b] || {};
          out.brackets[b].rating = Math.max(out.brackets[b].rating || 0, Number(it.rating));
          if (Number.isFinite(it.rank)) out.brackets[b].rank = Number(it.rank);
        }
      }
    }
  });

  return out;
}

async function main() {
  if (!REALM || !NAME) {
    console.error('Usage: REGION=eu REALM=ravencrest NAME=astrobloom node armory.js');
    process.exit(2);
  }
  const url = buildCharacterUrl(REGION, REALM, NAME);
  const html = await fetchHTML(url);
  const parsed = parseArmory(html);
  const result = { region: REGION, realm: REALM, name: NAME, url, ...parsed };
  try { fs.writeFileSync(OUT_JSON, JSON.stringify(result, null, 2), 'utf8'); } catch {}
  console.log(JSON.stringify(result, null, 2));
}

if (import.meta.url === `file://${__filename}`) {
  main().catch((err) => {
    console.error('armory error:', err && err.stack || err);
    process.exit(1);
  });
}
