import multer from 'multer'
import fs from 'fs/promises'
import path from 'path'
import { exec } from 'child_process'
import { promisify } from 'util'
import { getUserFromToken, hasAnyRole } from '../../utils/auth.js'
import { assertPdfMagicHeader } from '../../utils/upload-validation.js'

const execAsync = promisify(exec)

// Handle both dev and production paths
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
// filename is always a hardcoded constant ('satzung.json'), never user input
const getDataPath = (filename) => {
  const cwd = process.cwd()
  
  // In production (.output/server), working dir is .output
  if (cwd.endsWith('.output')) {
    // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
    return path.join(cwd, '../server/data', filename)
  }
  
  // In development, working dir is project root
  // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
  return path.join(cwd, 'server/data', filename)
}

// Multer-Konfiguration für PDF-Uploads
// Store uploads in internal data directory instead of public/
const DOCUMENTS_DIR = getDataPath('documents')

const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, DOCUMENTS_DIR)
  },
  filename: (req, file, cb) => {
    cb(null, 'satzung.pdf')
  }
})

const upload = multer({ 
  storage,
  fileFilter: (req, file, cb) => {
    if (file.mimetype === 'application/pdf') {
      cb(null, true)
    } else {
      cb(new Error('Nur PDF-Dateien sind erlaubt'), false)
    }
  },
  limits: {
    fileSize: 10 * 1024 * 1024 // 10MB Limit
  }
})

export default defineEventHandler(async (event) => {
  if (event.method !== 'POST') {
    throw createError({
      statusCode: 405,
      statusMessage: 'Method Not Allowed'
    })
  }

  let token = getCookie(event, 'auth_token')
  const currentUser = token ? await getUserFromToken(token) : null

  if (!currentUser) {
    throw createError({
      statusCode: 401,
      statusMessage: 'Nicht authentifiziert'
    })
  }

  if (!hasAnyRole(currentUser, 'admin', 'vorstand')) {
    throw createError({
      statusCode: 403,
      statusMessage: 'Keine Berechtigung'
    })
  }

    try {
      // Ensure internal documents dir exists
      await fs.mkdir(DOCUMENTS_DIR, { recursive: true })

    // Multer-Middleware für File-Upload
    await new Promise((resolve, reject) => {
      upload.single('pdf')(event.node.req, event.node.res, (err) => {
        if (err) reject(err)
        else resolve()
      })
    })

    const file = event.node.req.file
    if (!file) {
      throw createError({
        statusCode: 400,
        statusMessage: 'Keine PDF-Datei hochgeladen'
      })
    }

    // Zusätzliche Validierung: Magic-Bytes prüfen (mimetype kann gespooft sein)
    await assertPdfMagicHeader(file.path)

    // 1. Versuche, den Text mit pdftotext zu extrahieren
    let extractedText = ''
    try {
      // UTF-8 erzwingen, Ausgabe nach stdout
      const { stdout } = await execAsync(`pdftotext -enc UTF-8 "${file.path}" -`)
      extractedText = stdout || ''
    } catch (err) {
      console.error('pdftotext Fehler beim Verarbeiten der Satzung:', err)
      throw createError({
        statusCode: 500,
        statusMessage: 'Die Satzung konnte nicht aus dem PDF gelesen werden (pdftotext-Fehler). Bitte den Server-Administrator kontaktieren.'
      })
    }

    // Minimale Plausibilitätsprüfung: genug Text & typische Satzungs-Merkmale
    const cleaned = extractedText.trim()
    if (!cleaned || cleaned.length < 500 || !cleaned.includes('§')) {
      console.error('Satzung: extrahierter Text wirkt unplausibel oder zu kurz:', {
        length: cleaned.length
      })
      throw createError({
        statusCode: 500,
        statusMessage: 'Die Satzung konnte nicht zuverlässig aus dem PDF gelesen werden. Bitte die PDF-Datei prüfen.'
      })
    }

    // 2. In HTML-Format konvertieren
    const htmlContent = convertTextToHtml(cleaned)

    // 3. Config aktualisieren (PDF + geparster Inhalt)
    const configPath = getDataPath('config.json')
    const configData = JSON.parse(await fs.readFile(configPath, 'utf-8'))
    
    if (!configData.seiten) {
      configData.seiten = {}
    }

    // Serve the uploaded statute via internal media proxy
    configData.seiten.satzung = {
      pdfUrl: '/api/media/documents/satzung.pdf',
      content: htmlContent
    }
    
    await fs.writeFile(configPath, JSON.stringify(configData, null, 2), 'utf-8')
    
    return {
      success: true,
      message: 'Satzung erfolgreich hochgeladen und verarbeitet',
      pdfUrl: '/documents/satzung.pdf'
    }
    
  } catch (error) {
    console.error('PDF Upload Error:', error)
    if (error.statusCode) {
      throw error
    }
    throw createError({
      statusCode: 500,
      statusMessage: error.message || 'Fehler beim Verarbeiten der PDF-Datei'
    })
  }
})

// PDF-Text zu HTML konvertieren
function convertTextToHtml(text) {
  // Text bereinigen und strukturieren
  let cleaned = text
    .replace(/\r\n/g, '\n') // Windows-Zeilenumbrüche normalisieren
    .replace(/\r/g, '\n')   // Mac-Zeilenumbrüche normalisieren
    .trim()
  
  // Seitenzahlen und Seitenfuß entfernen
  cleaned = cleaned
    .replace(/^Seite\s+\d+\s+von\s+\d+.*$/gm, '')
    .replace(/^-+\d+-+\s*$/gm, '')
    .replace(/\n\s*-+\d+-+\s*\n/g, '\n')
    .replace(/\s*-+\d+-+\s*/g, '')
    .replace(/zuletzt geändert am \d{2}\.\d{2}\.\d{4}.*$/gm, '')
  
  // Zeilenweise aufteilen und leere Zeilen filtern
  let rawLines = cleaned.split('\n').map(l => l.trim()).filter(l => {
    if (!l || l.length === 0) return false
    if (/^-+\d+-+$/.test(l)) return false
    if (/^Seite\s+\d+\s+von\s+\d+/.test(l)) return false
    return true
  })
  
  // ============================================================
  // SCHRITT 1: Zusammengehörige Zeilen zusammenführen
  // pdftotext trennt oft Nummer/Prefix und Inhalt auf zwei Zeilen
  // ============================================================
  const merged = []
  for (let j = 0; j < rawLines.length; j++) {
    const line = rawLines[j]
    const next = j + 1 < rawLines.length ? rawLines[j + 1] : null
    
    // Fall 1: "§ 1" (nur Paragraphennummer) + nächste Zeile ist der Titel
    // z.B. "§ 1" + "Name, Sitz und Zweck" → "§ 1 Name, Sitz und Zweck"
    if (/^§\s*\d+\s*$/.test(line) && next && !next.match(/^§/) && !next.match(/^\d+\.\s/)) {
      merged.push(line + ' ' + next)
      j++ // nächste Zeile überspringen
      continue
    }
    
    // Fall 2: "1." (nur Nummer mit Punkt) + nächste Zeile ist der Text
    // z.B. "1." + "Der Harheimer TC..." → "1. Der Harheimer TC..."
    if (/^\d+\.\s*$/.test(line) && next) {
      merged.push(line + ' ' + next)
      j++
      continue
    }
    
    // Fall 3: "a)" (nur Buchstabe mit Klammer) + nächste Zeile ist der Text
    // z.B. "a)" + "Die Bestimmungen..." → "a) Die Bestimmungen..."
    if (/^[a-z]\)\s*$/i.test(line) && next) {
      merged.push(line + ' ' + next)
      j++
      continue
    }
    
    // Keine Zusammenführung nötig
    merged.push(line)
  }
  
  // ============================================================
  // SCHRITT 2: HTML-Elemente erzeugen
  // ============================================================
  const result = []
  let i = 0
  
  while (i < merged.length) {
    const line = merged[i]
    
    // Überschriften erkennen (§1, § 2, etc.)
    if (line.match(/^§\s*\d+/)) {
      result.push(`<h2>${line}</h2>`)
      i++
      continue
    }
    
    // Prüfe ob wir eine Liste mit a), b), c) haben
    // Suche nach einem Muster wie "2. Text:" gefolgt von "a) ...", "b) ...", etc.
    if (line.match(/^\d+\.\s+.*:$/) && i + 1 < merged.length && merged[i + 1].match(/^[a-z]\)\s+/i)) {
      // Einleitender Text für die Liste (ohne Nummer)
      const introText = line.replace(/^\d+\.\s+/, '')
      const listItems = []
      i++
      
      // Sammle alle Listenpunkte a), b), c) ...
      while (i < merged.length && merged[i].match(/^[a-z]\)\s+/i)) {
        const itemText = merged[i].replace(/^[a-z]\)\s+/i, '').trim()
        if (itemText) {
          listItems.push(itemText)
        }
        i++
      }
      
      if (listItems.length > 0) {
        const listHtml = listItems.map(item => `<li>${item}</li>`).join('')
        result.push(`<p><strong>${introText}</strong></p><ul>${listHtml}</ul>`)
      } else {
        result.push(`<p>${line}</p>`)
      }
      continue
    }
    
    // Einzelne Listenpunkte a), b), c) erkennen
    if (line.match(/^[a-z]\)\s+/i)) {
      const items = []
      while (i < merged.length && merged[i].match(/^[a-z]\)\s+/i)) {
        const itemText = merged[i].replace(/^[a-z]\)\s+/i, '').trim()
        if (itemText) {
          items.push(itemText)
        }
        i++
      }
      if (items.length > 0) {
        const listHtml = items.map(item => `<li>${item}</li>`).join('')
        result.push(`<ul>${listHtml}</ul>`)
      }
      continue
    }
    
    // Nummerierte Listen (1., 2., 3.) - aber nur wenn mehrere aufeinander folgen
    if (line.match(/^\d+\.\s+/) && i + 1 < merged.length && merged[i + 1].match(/^\d+\.\s+/)) {
      const items = []
      while (i < merged.length && merged[i].match(/^\d+\.\s+/)) {
        const itemText = merged[i].replace(/^\d+\.\s+/, '').trim()
        // Prüfe ob es eine Einleitung für eine Unterliste ist (endet mit ":")
        if (itemText.endsWith(':') && i + 1 < merged.length && merged[i + 1].match(/^[a-z]\)\s+/i)) {
          break // Wird oben als Einleitung + Unterliste behandelt
        }
        if (itemText) {
          items.push(itemText)
        }
        i++
      }
      if (items.length > 0) {
        const listHtml = items.map(item => `<li>${item}</li>`).join('')
        result.push(`<ol>${listHtml}</ol>`)
      }
      continue
    }
    
    // Normale Absätze
    result.push(`<p>${line}</p>`)
    i++
  }
  
  let html = result.join('\n')
  
  // Leere Absätze entfernen
  html = html.replace(/<p>\s*<\/p>/g, '')
  html = html.replace(/<p><\/p>/g, '')
  
  return html.trim()
}
