const fs = require('fs');
const path = require('path');

function ensureDir(dirPath) {
  fs.mkdirSync(dirPath, { recursive: true });
}

function transliterateForFilename(input) {
  return String(input || '')
    // German — must come before NFD to get ae/oe/ue instead of just a/o/u
    .replace(/ä/g, 'ae').replace(/Ä/g, 'Ae')
    .replace(/ö/g, 'oe').replace(/Ö/g, 'Oe')
    .replace(/ü/g, 'ue').replace(/Ü/g, 'Ue')
    .replace(/ß/g, 'ss')
    // Danish / Norwegian / Swedish
    .replace(/å/g, 'a').replace(/Å/g, 'A')
    .replace(/æ/g, 'ae').replace(/Æ/g, 'Ae')
    .replace(/ø/g, 'o').replace(/Ø/g, 'O')
    // Icelandic
    .replace(/ð/g, 'd').replace(/Ð/g, 'D')
    .replace(/þ/g, 'th').replace(/Þ/g, 'Th')
    // NFD decomposition + strip combining diacritical marks (handles é→e, ñ→n, ç→c, etc.)
    .normalize('NFD')
    .replace(/\p{M}+/gu, '')
    // Drop any remaining non-ASCII characters
    .replace(/[^\x00-\x7F]/g, '');
}

function sanitizeFileName(input) {
  return transliterateForFilename(String(input || 'untitled'))
    .replace(/[^a-zA-Z0-9 ()[\]_-]/g, '')
    .replace(/\s+/g, ' ')
    .trim()
    .slice(0, 180);
}

function sanitizeFileNameWithExtension(input) {
  const str = String(input || 'untitled');
  const ext = path.extname(str);
  const base = ext ? str.slice(0, -ext.length) : str;
  const cleanBase = sanitizeFileName(base);
  const cleanExt = ext.toLowerCase().replace(/[^a-z0-9.]/g, '');
  return (cleanBase || 'untitled') + cleanExt;
}

function renderTemplate(template, values) {
  const rawSource = String(template || '${title} (${year})');
  const parseToken = (rawToken) => {
    const token = String(rawToken || '').trim();
    if (!token) {
      return { format: '', key: '' };
    }
    const separatorIndex = token.indexOf(':');
    if (separatorIndex <= 0) {
      return { format: '', key: token };
    }
    return {
      format: token.slice(0, separatorIndex).trim(),
      key: token.slice(separatorIndex + 1).trim()
    };
  };
  const applyFormat = (value, format) => {
    const normalizedFormat = String(format || '').trim().toLowerCase();
    if (!normalizedFormat) {
      return String(value);
    }
    // {0:key} => number with leading zero (width 2), e.g. 2 -> 02
    if (normalizedFormat === '0') {
      const raw = String(value);
      const match = raw.match(/^(-?)(\d+)$/);
      if (match) {
        const sign = match[1] || '';
        const digits = String(match[2] || '');
        return `${sign}${digits.padStart(2, '0')}`;
      }
    }
    return String(value);
  };
  const resolveToken = (rawKey) => {
    const { format, key } = parseToken(rawKey);
    const val = values[key];
    if (val === undefined || val === null || val === '') {
      return 'unknown';
    }
    return applyFormat(val, format);
  };

  const source = (
    /[{}]/.test(rawSource)
      ? rawSource
      : rawSource.replace(/\b(trackNr|trackNumber|artist|album|title|year)\b/g, '{$1}')
  );

  // Support both ${key} and legacy {key} placeholders (+ recovered bare tokens).
  return source
    .replace(/\$\{([^}]+)\}/g, (_m, key) => resolveToken(key))
    .replace(/\{([^{}$]+)\}/g, (_m, key) => resolveToken(key));
}

function findLargestMediaFile(dirPath, extensions = ['.mkv', '.mp4']) {
  const files = findMediaFiles(dirPath, extensions);
  if (files.length === 0) {
    return null;
  }

  return files.reduce((largest, file) => (largest === null || file.size > largest.size ? file : largest), null);
}

function findMediaFiles(dirPath, extensions = ['.mkv', '.mp4']) {
  const results = [];

  function walk(current) {
    const entries = fs.readdirSync(current, { withFileTypes: true });
    for (const entry of entries) {
      const abs = path.join(current, entry.name);
      if (entry.isDirectory()) {
        walk(abs);
      } else {
        const ext = path.extname(entry.name).toLowerCase();
        if (!extensions.includes(ext)) {
          continue;
        }

        const stat = fs.statSync(abs);
        results.push({
          path: abs,
          size: stat.size
        });
      }
    }
  }

  walk(dirPath);
  results.sort((a, b) => b.size - a.size || a.path.localeCompare(b.path));
  return results;
}

module.exports = {
  ensureDir,
  transliterateForFilename,
  sanitizeFileName,
  sanitizeFileNameWithExtension,
  renderTemplate,
  findLargestMediaFile,
  findMediaFiles
};
