import fs from 'fs/promises'
import path from 'path'
import { readMembers } from './members.js'
import { readUsers } from './auth.js'
import { encryptObject, decryptObject } from './encryption.js'
import crypto from 'crypto'

// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
// filename is always a hardcoded constant (e.g., 'newsletter-subscribers.json'), never user input
const getDataPath = (filename) => {
  const cwd = process.cwd()
  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)
  }
  // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
  return path.join(cwd, 'server/data', filename)
}

const NEWSLETTER_SUBSCRIBERS_FILE = getDataPath('newsletter-subscribers.json')

function getEncryptionKey() {
  return process.env.ENCRYPTION_KEY || 'local_development_encryption_key_change_in_production'
}

// Liste möglicher alter Verschlüsselungsschlüssel (für Migration)
function getPossibleEncryptionKeys() {
  const currentKey = getEncryptionKey()
  const oldKeys = [
    'default-key-change-in-production',
    'local_development_encryption_key_change_in_production'
  ]
  
  // Aktueller Schlüssel zuerst, dann alte Schlüssel
  const keys = [currentKey]
  for (const oldKey of oldKeys) {
    if (oldKey !== currentKey) {
      keys.push(oldKey)
    }
  }
  
  // Optional: Alter Schlüssel aus Environment-Variable
  if (process.env.OLD_ENCRYPTION_KEY && process.env.OLD_ENCRYPTION_KEY !== currentKey) {
    keys.push(process.env.OLD_ENCRYPTION_KEY)
  }
  
  return keys
}

// Prüft ob Daten verschlüsselt sind
function isEncrypted(data) {
  try {
    const parsed = JSON.parse(data.trim())
    if (Array.isArray(parsed)) {
      return false
    }
    if (typeof parsed === 'object' && parsed !== null && !parsed.encryptedData) {
      return false
    }
    return false
  } catch (_e) {
    return true
  }
}

export async function readSubscribers() {
  try {
    const data = await fs.readFile(NEWSLETTER_SUBSCRIBERS_FILE, 'utf-8')
    const encrypted = isEncrypted(data)
    
    if (encrypted) {
      // Versuche mit verschiedenen Schlüsseln zu entschlüsseln (für Migration)
      const possibleKeys = getPossibleEncryptionKeys()
      const encryptionKey = getEncryptionKey()
      
      let lastError = null
      for (let i = 0; i < possibleKeys.length; i++) {
        const key = possibleKeys[i]
        try {
          const decrypted = decryptObject(data, key)
          
          // Wenn mit altem Schlüssel entschlüsselt wurde, warnen und neu verschlüsseln
          if (i > 0 && key !== encryptionKey) {
            console.warn(`⚠️  Newsletter-Abonnenten wurden mit altem Schlüssel entschlüsselt. Automatische Neuverschlüsselung...`)
            try {
              await writeSubscribers(decrypted)
              console.log('✅ Newsletter-Abonnenten erfolgreich mit neuem Schlüssel neu verschlüsselt')
            } catch (writeError) {
              console.error('❌ Fehler beim Neuverschlüsseln:', writeError.message)
              console.error('   Bitte führen Sie manuell aus: node scripts/re-encrypt-data.js')
            }
          }
          
          return decrypted
        } catch (decryptError) {
          lastError = decryptError
          // Versuche nächsten Schlüssel
          continue
        }
      }
      
      // Alle Schlüssel fehlgeschlagen
      console.error('Fehler beim Entschlüsseln der Newsletter-Abonnenten:')
      console.error('  Versuchte Schlüssel:', possibleKeys.length)
      console.error('  Letzter Fehler:', lastError?.message || 'Unbekannter Fehler')
      console.error('')
      console.error('💡 Lösung: Führen Sie das Re-Encrypt-Skript aus:')
      console.error('   node scripts/re-encrypt-data.js --old-key="<alter-schlüssel>"')
      console.error('   Oder setzen Sie OLD_ENCRYPTION_KEY als Environment-Variable')
      
      // Fallback: try to read as plain JSON
      try {
        const plainData = JSON.parse(data)
        console.warn('Entschlüsselung fehlgeschlagen, versuche als unverschlüsseltes Format zu lesen')
        return plainData
      } catch (_parseError) {
        console.error('Konnte Newsletter-Abonnenten weder entschlüsseln noch als JSON lesen')
        return []
      }
    } else {
      // Plain JSON - migriere zu verschlüsselter Speicherung
      const subscribers = JSON.parse(data)
      console.log('Migriere unverschlüsselte Newsletter-Abonnenten zu verschlüsselter Speicherung...')
      await writeSubscribers(subscribers)
      return subscribers
    }
  } catch (error) {
    if (error.code === 'ENOENT') {
      return []
    }
    throw error
  }
}

export async function writeSubscribers(subscribers) {
  try {
    const encryptionKey = getEncryptionKey()
    const encryptedData = encryptObject(subscribers, encryptionKey)
    await fs.writeFile(NEWSLETTER_SUBSCRIBERS_FILE, encryptedData, 'utf-8')
    return true
  } catch (error) {
    console.error('Fehler beim Schreiben der Newsletter-Abonnenten:', error)
    return false
  }
}

// Berechnet Alter aus Geburtsdatum
function calculateAge(geburtsdatum) {
  if (!geburtsdatum) return null
  try {
    const birthDate = new Date(geburtsdatum)
    const today = new Date()
    let age = today.getFullYear() - birthDate.getFullYear()
    const monthDiff = today.getMonth() - birthDate.getMonth()
    if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
      age--
    }
    return age
  } catch {
    return null
  }
}

// Filtert den Admin-User aus Empfängerliste heraus
function filterAdminUser(recipients) {
  return recipients.filter(r => {
    const email = (r.email || '').toLowerCase().trim()
    return email !== 'admin@harheimertc.de'
  })
}

// Filtert Mitglieder nach Zielgruppe
export async function getRecipientsByGroup(targetGroup) {
  const members = await readMembers()
  const users = await readUsers()
  
  let recipients = []

  switch (targetGroup) {
    case 'alle':
      // Alle Mitglieder mit E-Mail
      recipients = members
        .filter(m => m.email && m.email.trim() !== '')
        .map(m => ({
          email: m.email,
          name: `${m.firstName || ''} ${m.lastName || ''}`.trim() || m.name || ''
        }))
      // Auch alle aktiven Benutzer hinzufügen
      users
        .filter(u => u.active && u.email)
        .forEach(u => {
          if (!recipients.find(r => r.email.toLowerCase() === u.email.toLowerCase())) {
            recipients.push({
              email: u.email,
              name: u.name || ''
            })
          }
        })
      break

    case 'erwachsene':
      // Mitglieder über 18 Jahre
      recipients = members
        .filter(m => {
          if (!m.email || !m.email.trim()) return false
          const age = calculateAge(m.geburtsdatum)
          return age !== null && age >= 18
        })
        .map(m => ({
          email: m.email.trim(),
          name: `${m.firstName || ''} ${m.lastName || ''}`.trim() || m.name || ''
        }))
      // Auch aktive Benutzer hinzufügen (als Erwachsene behandelt, wenn kein Geburtsdatum)
      users
        .filter(u => u.active && u.email && u.email.trim())
        .forEach(u => {
          // Prüfe ob bereits vorhanden
          if (!recipients.find(r => r.email.toLowerCase() === u.email.toLowerCase().trim())) {
            recipients.push({
              email: u.email.trim(),
              name: u.name || ''
            })
          }
        })
      break

    case 'nachwuchs':
      // Mitglieder unter 18 Jahre
      recipients = members
        .filter(m => {
          if (!m.email || !m.email.trim()) return false
          const age = calculateAge(m.geburtsdatum)
          return age !== null && age < 18
        })
        .map(m => ({
          email: m.email,
          name: `${m.firstName || ''} ${m.lastName || ''}`.trim() || m.name || ''
        }))

      // Zusätzlich aktive Trainer aus users.json anschreiben
      users
        .filter(u => {
          if (!u.active || !u.email || !u.email.trim()) return false
          const roles = Array.isArray(u.roles) ? u.roles : (u.role ? [u.role] : [])
          return roles.includes('trainer')
        })
        .forEach(u => {
          if (!recipients.find(r => r.email.toLowerCase().trim() === u.email.toLowerCase().trim())) {
            recipients.push({
              email: u.email.trim(),
              name: u.name || ''
            })
          }
        })
      break

    case 'mannschaftsspieler':
      // Mitglieder die in einer Mannschaft spielen
      recipients = members
        .filter(m => {
          if (!m.email || !m.email.trim()) return false
          // Prüfe ob als Mannschaftsspieler markiert
          if (m.isMannschaftsspieler === true) {
            return true
          }
          // Fallback: Prüfe ob in notes etwas über Mannschaft steht (für Rückwärtskompatibilität)
          const notes = (m.notes || '').toLowerCase()
          return notes.includes('mannschaft') || notes.includes('spieler')
        })
        .map(m => ({
          email: m.email,
          name: `${m.firstName || ''} ${m.lastName || ''}`.trim() || m.name || ''
        }))
      break

    case 'vorstand':
      // Nur Vorstand (aus users.json)
      recipients = users
        .filter(u => {
          if (!u.active || !u.email) return false
          const roles = Array.isArray(u.roles) ? u.roles : (u.role ? [u.role] : [])
          return roles.includes('admin') || roles.includes('vorstand')
        })
        .map(u => ({
          email: u.email,
          name: u.name || ''
        }))
      break

    default:
      recipients = []
  }

  // Admin-User herausfiltern
  return filterAdminUser(recipients)
}

// Holt Newsletter-Abonnenten (bestätigt und nicht abgemeldet)
export async function getNewsletterSubscribers(internalOnly = false, groupId = null) {
  const subscribers = await readSubscribers()
  
  let confirmedSubscribers = subscribers.filter(s => {
    if (!s.confirmed || s.unsubscribedAt) {
      return false
    }
    
    // Wenn groupId angegeben ist, prüfe ob Subscriber für diese Gruppe angemeldet ist
    if (groupId) {
      // Stelle sicher, dass groupIds existiert (für Rückwärtskompatibilität)
      if (!s.groupIds || !Array.isArray(s.groupIds)) {
        return false
      }
      return s.groupIds.includes(groupId)
    }
    
    // Wenn keine groupId angegeben, prüfe ob Subscriber für mindestens eine Gruppe angemeldet ist
    // (für Rückwärtskompatibilität: wenn keine groupIds vorhanden, als abonniert behandeln)
    if (s.groupIds && Array.isArray(s.groupIds)) {
      return s.groupIds.length > 0
    }
    
    // Rückwärtskompatibilität: alte Subscriber ohne groupIds werden als abonniert behandelt
    return true
  })

  if (internalOnly) {
    // Nur interne Abonnenten (die auch Mitglieder sind)
    const members = await readMembers()
    const memberEmails = new Set(
      members
        .filter(m => m.email)
        .map(m => m.email.toLowerCase())
    )
    
    confirmedSubscribers = confirmedSubscribers.filter(s => 
      memberEmails.has(s.email.toLowerCase())
    )
  }

  const result = confirmedSubscribers.map(s => ({
    email: s.email,
    name: s.name || ''
  }))
  
  // Admin-User herausfiltern
  return filterAdminUser(result)
}

// Generiert Abmelde-Token für Abonnenten
export async function generateUnsubscribeToken(email) {
  const subscribers = await readSubscribers()
  const subscriber = subscribers.find(s => s.email.toLowerCase() === email.toLowerCase())
  
  if (!subscriber) {
    return null
  }

  if (!subscriber.unsubscribeToken) {
    subscriber.unsubscribeToken = crypto.randomBytes(32).toString('hex')
    await writeSubscribers(subscribers)
  }

  return subscriber.unsubscribeToken
}

