/**
 * TASKMATE - File Upload
 * ======================
 * Multer-Konfiguration für Datei-Uploads
 */

const multer = require('multer');
const path = require('path');
const fs = require('fs');
const crypto = require('crypto');
const { v4: uuidv4 } = require('uuid');
const logger = require('../utils/logger');

// Upload-Verzeichnis
const UPLOAD_DIR = process.env.UPLOAD_DIR || path.join(__dirname, '..', 'uploads');

// Verzeichnis erstellen falls nicht vorhanden
if (!fs.existsSync(UPLOAD_DIR)) {
  fs.mkdirSync(UPLOAD_DIR, { recursive: true });
}

// Mapping: Dateiendung -> erlaubte MIME-Types
const EXTENSION_TO_MIME = {
  // Dokumente
  'pdf': ['application/pdf'],
  'doc': ['application/msword'],
  'docx': ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
  'xls': ['application/vnd.ms-excel'],
  'xlsx': ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
  'ppt': ['application/vnd.ms-powerpoint'],
  'pptx': ['application/vnd.openxmlformats-officedocument.presentationml.presentation'],
  'odt': ['application/vnd.oasis.opendocument.text'],
  'ods': ['application/vnd.oasis.opendocument.spreadsheet'],
  'odp': ['application/vnd.oasis.opendocument.presentation'],
  'rtf': ['application/rtf', 'text/rtf'],
  // Text
  'txt': ['text/plain'],
  'csv': ['text/csv', 'application/csv', 'text/comma-separated-values'],
  'md': ['text/markdown', 'text/x-markdown', 'text/plain'],
  'json': ['application/json', 'text/json'],
  'xml': ['application/xml', 'text/xml'],
  'html': ['text/html'],
  'log': ['text/plain'],
  // Bilder
  'jpg': ['image/jpeg'],
  'jpeg': ['image/jpeg'],
  'png': ['image/png'],
  'gif': ['image/gif'],
  'webp': ['image/webp'],
  'svg': ['image/svg+xml'],
  'bmp': ['image/bmp'],
  'ico': ['image/x-icon', 'image/vnd.microsoft.icon'],
  // Archive
  'zip': ['application/zip', 'application/x-zip-compressed'],
  'rar': ['application/x-rar-compressed', 'application/vnd.rar'],
  '7z': ['application/x-7z-compressed'],
  'tar': ['application/x-tar'],
  'gz': ['application/gzip', 'application/x-gzip'],
  // Code/Skripte (als text/plain akzeptiert)
  'sql': ['application/sql', 'text/plain'],
  'js': ['text/javascript', 'application/javascript', 'text/plain'],
  'css': ['text/css', 'text/plain'],
  'py': ['text/x-python', 'text/plain'],
  'sh': ['application/x-sh', 'text/plain']
};

// Standard-Werte (Fallback)
let MAX_FILE_SIZE = (parseInt(process.env.MAX_FILE_SIZE_MB) || 15) * 1024 * 1024;
let ALLOWED_EXTENSIONS = ['pdf', 'docx', 'txt'];

/**
 * Lädt Upload-Einstellungen aus der Datenbank
 */
function loadUploadSettings() {
  try {
    // Lazy-Load um zirkuläre Abhängigkeiten zu vermeiden
    const { getUploadSettings } = require('../routes/admin');
    const settings = getUploadSettings();

    if (settings) {
      MAX_FILE_SIZE = (settings.maxFileSizeMB || 15) * 1024 * 1024;

      // Erlaubte Endungen aus den Einstellungen
      if (Array.isArray(settings.allowedExtensions) && settings.allowedExtensions.length > 0) {
        ALLOWED_EXTENSIONS = settings.allowedExtensions;
      }
    }
  } catch (error) {
    // Bei Fehler Standard-Werte beibehalten
    logger.warn('Upload-Einstellungen konnten nicht geladen werden, verwende Standards');
  }
}

/**
 * Aktuelle Einstellungen abrufen (für dynamische Prüfung)
 */
function getCurrentSettings() {
  loadUploadSettings();
  return { maxFileSize: MAX_FILE_SIZE, allowedExtensions: ALLOWED_EXTENSIONS };
}

/**
 * Storage-Konfiguration
 */
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    // Task-ID aus URL oder Body
    const taskId = req.params.taskId || req.body.taskId;

    if (taskId) {
      // Unterordner pro Task
      const taskDir = path.join(UPLOAD_DIR, `task_${taskId}`);
      if (!fs.existsSync(taskDir)) {
        fs.mkdirSync(taskDir, { recursive: true });
      }
      cb(null, taskDir);
    } else {
      cb(null, UPLOAD_DIR);
    }
  },

  filename: (req, file, cb) => {
    // Eindeutiger Dateiname mit Original-Extension
    const ext = path.extname(file.originalname).toLowerCase();
    const uniqueName = `${uuidv4()}${ext}`;
    cb(null, uniqueName);
  }
});

/**
 * Gefährliche Dateinamen prüfen
 */
function isSecureFilename(filename) {
  // Null-Bytes, Pfad-Traversal, Steuerzeichen blocken
  const dangerousPatterns = [
    /\x00/,           // Null-Bytes
    /\.\./,           // Path traversal
    /[<>:"\\|?*]/,    // Windows-spezifische gefährliche Zeichen
    /[\x00-\x1F]/,    // Steuerzeichen
    /^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(\.|$)/i, // Windows reservierte Namen
  ];
  
  return !dangerousPatterns.some(pattern => pattern.test(filename));
}

/**
 * Datei-Filter: Erweiterte Sicherheitsprüfungen
 */
const fileFilter = (req, file, cb) => {
  // Aktuelle Einstellungen laden
  const settings = getCurrentSettings();

  // Sicherheitsprüfungen für Dateinamen
  if (!isSecureFilename(file.originalname)) {
    logger.warn(`Unsicherer Dateiname abgelehnt: ${file.originalname}`);
    cb(new Error('Dateiname enthält nicht erlaubte Zeichen'), false);
    return;
  }

  // Dateiname-Länge prüfen
  if (file.originalname.length > 255) {
    logger.warn(`Dateiname zu lang: ${file.originalname}`);
    cb(new Error('Dateiname ist zu lang (max. 255 Zeichen)'), false);
    return;
  }

  // Dateiendung extrahieren (ohne Punkt, lowercase)
  const ext = path.extname(file.originalname).toLowerCase().replace('.', '');
  
  // Doppelte Dateiendungen verhindern (z.B. script.txt.exe)
  const nameWithoutExt = path.basename(file.originalname, path.extname(file.originalname));
  if (path.extname(nameWithoutExt)) {
    logger.warn(`Doppelte Dateiendung abgelehnt: ${file.originalname}`);
    cb(new Error('Dateien mit mehreren Endungen sind nicht erlaubt'), false);
    return;
  }

  // Prüfen ob Endung erlaubt ist
  if (!settings.allowedExtensions.includes(ext)) {
    logger.warn(`Abgelehnter Upload (Endung): ${file.originalname} (.${ext})`);
    cb(new Error(`Dateityp .${ext} nicht erlaubt`), false);
    return;
  }

  // Executable Dateien zusätzlich blocken
  const executableExtensions = [
    'exe', 'bat', 'cmd', 'com', 'scr', 'pif', 'vbs', 'vbe', 'js', 'jar',
    'app', 'deb', 'pkg', 'dmg', 'run', 'bin', 'msi', 'gadget'
  ];
  if (executableExtensions.includes(ext)) {
    logger.warn(`Executable Datei abgelehnt: ${file.originalname}`);
    cb(new Error('Ausführbare Dateien sind nicht erlaubt'), false);
    return;
  }

  // MIME-Type gegen bekannte Typen prüfen
  const expectedMimes = EXTENSION_TO_MIME[ext];
  if (expectedMimes && !expectedMimes.includes(file.mimetype)) {
    logger.warn(`MIME-Mismatch: ${file.originalname} (erwartet: ${expectedMimes.join('/')}, bekommen: ${file.mimetype})`);
    // Bei kritischen Mismatches ablehnen
    if (file.mimetype === 'application/octet-stream' || file.mimetype.startsWith('application/x-')) {
      cb(new Error('Verdächtiger Dateityp erkannt'), false);
      return;
    }
  }

  cb(null, true);
};

/**
 * Dynamische Multer-Instanz erstellen
 */
function createUpload() {
  const settings = getCurrentSettings();
  return multer({
    storage,
    fileFilter,
    limits: {
      fileSize: settings.maxFileSize,
      files: 10 // Maximal 10 Dateien pro Request
    }
  });
}

// Standard-Instanz für Rückwärtskompatibilität
const upload = createUpload();

/**
 * Datei löschen
 */
function deleteFile(filePath) {
  try {
    const fullPath = path.join(UPLOAD_DIR, filePath);
    if (fs.existsSync(fullPath)) {
      fs.unlinkSync(fullPath);
      logger.info(`Datei gelöscht: ${filePath}`);
      return true;
    }
    return false;
  } catch (error) {
    logger.error(`Fehler beim Löschen: ${filePath}`, { error: error.message });
    return false;
  }
}

/**
 * Dateigröße formatieren
 */
function formatFileSize(bytes) {
  if (bytes === 0) return '0 Bytes';

  const k = 1024;
  const sizes = ['Bytes', 'KB', 'MB', 'GB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));

  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}

/**
 * Ist Bild?
 */
function isImage(mimeType) {
  return mimeType && mimeType.startsWith('image/');
}

/**
 * Datei-Icon basierend auf MIME-Type
 */
function getFileIcon(mimeType) {
  if (mimeType.startsWith('image/')) return 'image';
  if (mimeType === 'application/pdf') return 'pdf';
  if (mimeType.includes('word')) return 'word';
  if (mimeType.includes('excel') || mimeType.includes('spreadsheet')) return 'excel';
  if (mimeType.includes('powerpoint') || mimeType.includes('presentation')) return 'powerpoint';
  if (mimeType.includes('zip') || mimeType.includes('rar') || mimeType.includes('7z')) return 'archive';
  if (mimeType.startsWith('text/')) return 'text';
  return 'file';
}

module.exports = {
  upload,
  createUpload,
  deleteFile,
  formatFileSize,
  isImage,
  getFileIcon,
  getCurrentSettings,
  UPLOAD_DIR,
  MAX_FILE_SIZE,
  ALLOWED_EXTENSIONS,
  EXTENSION_TO_MIME
};
