import { readSubscribers, writeSubscribers } from '../../utils/newsletter.js'
import { randomUUID } from 'crypto'
import nodemailer from 'nodemailer'
import crypto from 'crypto'
import fs from 'fs/promises'
import path from 'path'
import { assertRateLimit, getClientIp, registerRateLimitFailure, registerRateLimitSuccess } from '../../utils/rate-limit.js'
import { getUserFromToken } from '../../utils/auth.js'

// 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_GROUPS_FILE = getDataPath('newsletter-groups.json')

async function readGroups() {
  try {
    const data = await fs.readFile(NEWSLETTER_GROUPS_FILE, 'utf-8')
    return JSON.parse(data)
  } catch (error) {
    if (error.code === 'ENOENT') {
      return []
    }
    throw error
  }
}

export default defineEventHandler(async (event) => {
  try {
    const body = await readBody(event)
    const { email, name, groupId } = body

    if (!email || !email.match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/)) {
      throw createError({
        statusCode: 400,
        statusMessage: 'Ungültige E-Mail-Adresse'
      })
    }

    const ip = getClientIp(event)
    const emailKey = String(email || '').trim().toLowerCase()
    assertRateLimit(event, {
      name: 'newsletter:subscribe:ip',
      keyParts: [ip],
      windowMs: 10 * 60 * 1000,
      maxAttempts: 30,
      lockoutMs: 15 * 60 * 1000
    })
    assertRateLimit(event, {
      name: 'newsletter:subscribe:email',
      keyParts: [emailKey],
      windowMs: 10 * 60 * 1000,
      maxAttempts: 8,
      lockoutMs: 30 * 60 * 1000
    })

    if (!groupId) {
      throw createError({
        statusCode: 400,
        statusMessage: 'Newsletter-Gruppe muss ausgewählt werden'
      })
    }

    // Prüfe ob Gruppe existiert und für externe Abonnements verfügbar ist
    const groups = await readGroups()
    const group = groups.find(g => g.id === groupId)
    
    if (!group) {
      throw createError({
        statusCode: 404,
        statusMessage: 'Newsletter-Gruppe nicht gefunden'
      })
    }

    // Prüfe ob Benutzer eingeloggt ist
    let isLoggedIn = false
    try {
      const token = getCookie(event, 'auth_token') || getHeader(event, 'authorization')?.replace('Bearer ', '')
      if (token) {
        const user = await getUserFromToken(token)
        if (user && user.active) {
          isLoggedIn = true
        }
      }
    } catch (_e) {
      // Nicht eingeloggt - kein Problem
    }

    // Prüfe ob Gruppe für Abonnements verfügbar ist
    if (group.type !== 'subscription') {
      throw createError({
        statusCode: 403,
        statusMessage: 'Diese Newsletter-Gruppe ist nicht für Abonnements verfügbar'
      })
    }

    // Nicht eingeloggte Benutzer können sich nur für externe Newsletter anmelden
    if (!isLoggedIn && group.sendToExternal !== true) {
      throw createError({
        statusCode: 403,
        statusMessage: 'Diese Newsletter-Gruppe ist nur für Mitglieder verfügbar. Bitte melden Sie sich an.'
      })
    }

    const subscribers = await readSubscribers()
    const emailLower = email.toLowerCase()
    
    // Prüfe ob bereits für diese Gruppe angemeldet
    const existing = subscribers.find(s => {
      const sEmail = (s.email || '').toLowerCase()
      return sEmail === emailLower && s.groupIds && s.groupIds.includes(groupId)
    })
    
    if (existing) {
      if (existing.confirmed) {
        await registerRateLimitFailure(event, { name: 'newsletter:subscribe:ip', keyParts: [ip] })
        await registerRateLimitFailure(event, { name: 'newsletter:subscribe:email', keyParts: [emailKey] })
        throw createError({
          statusCode: 409,
          statusMessage: 'Sie sind bereits für diesen Newsletter angemeldet'
        })
      } else {
        // Bestätigungsmail erneut senden
        await sendConfirmationEmail(existing.email, existing.name || name, existing.confirmationToken, group.name)
        registerRateLimitSuccess(event, { name: 'newsletter:subscribe:email', keyParts: [emailKey] })
        return {
          success: true,
          message: 'Eine Bestätigungsmail wurde an Ihre E-Mail-Adresse gesendet'
        }
      }
    }

    // Prüfe ob E-Mail bereits existiert (für andere Gruppe oder ohne Gruppe)
    const existingEmail = subscribers.find(s => (s.email || '').toLowerCase() === emailLower)
    
    if (existingEmail) {
      // Bestehender Subscriber - Gruppe hinzufügen
      if (!existingEmail.groupIds) {
        existingEmail.groupIds = []
      }
      
      if (existingEmail.groupIds.includes(groupId)) {
        // Bereits für diese Gruppe angemeldet
        if (existingEmail.confirmed) {
          await registerRateLimitFailure(event, { name: 'newsletter:subscribe:ip', keyParts: [ip] })
          await registerRateLimitFailure(event, { name: 'newsletter:subscribe:email', keyParts: [emailKey] })
          throw createError({
            statusCode: 409,
            statusMessage: 'Sie sind bereits für diesen Newsletter angemeldet'
          })
        } else {
          // Bestätigungsmail erneut senden
          await sendConfirmationEmail(existingEmail.email, existingEmail.name || name, existingEmail.confirmationToken, group.name)
          registerRateLimitSuccess(event, { name: 'newsletter:subscribe:email', keyParts: [emailKey] })
          return {
            success: true,
            message: 'Eine Bestätigungsmail wurde an Ihre E-Mail-Adresse gesendet'
          }
        }
      }
      
      // Gruppe hinzufügen
      existingEmail.groupIds.push(groupId)
      if (!existingEmail.confirmed) {
        // Neuer Bestätigungstoken für alle Gruppen
        existingEmail.confirmationToken = crypto.randomBytes(32).toString('hex')
      }
      existingEmail.name = name || existingEmail.name || ''
      
      await writeSubscribers(subscribers)
      
      if (existingEmail.confirmed) {
        // Bereits bestätigt - sofort aktiviert
        registerRateLimitSuccess(event, { name: 'newsletter:subscribe:email', keyParts: [emailKey] })
        return {
          success: true,
          message: `Sie wurden erfolgreich für den Newsletter "${group.name}" angemeldet`
        }
      } else {
        // Bestätigungsmail senden
        await sendConfirmationEmail(existingEmail.email, existingEmail.name, existingEmail.confirmationToken, group.name)
        registerRateLimitSuccess(event, { name: 'newsletter:subscribe:email', keyParts: [emailKey] })
        return {
          success: true,
          message: 'Eine Bestätigungsmail wurde an Ihre E-Mail-Adresse gesendet. Bitte bestätigen Sie Ihre Anmeldung.'
        }
      }
    }

    // Neuer Abonnent
    const confirmationToken = crypto.randomBytes(32).toString('hex')
    const unsubscribeToken = crypto.randomBytes(32).toString('hex')
    const newSubscriber = {
      id: randomUUID(),
      email: emailLower,
      name: name || '',
      groupIds: [groupId],
      confirmed: false,
      confirmationToken,
      unsubscribeToken,
      subscribedAt: new Date().toISOString(),
      confirmedAt: null,
      unsubscribedAt: null
    }

    subscribers.push(newSubscriber)
    await writeSubscribers(subscribers)

    // Bestätigungsmail senden
    await sendConfirmationEmail(email, name, confirmationToken, group.name)

    registerRateLimitSuccess(event, { name: 'newsletter:subscribe:email', keyParts: [emailKey] })
    return {
      success: true,
      message: 'Eine Bestätigungsmail wurde an Ihre E-Mail-Adresse gesendet. Bitte bestätigen Sie Ihre Anmeldung.'
    }
  } catch (error) {
    console.error('Fehler bei Newsletter-Anmeldung:', error)
    if (error.statusCode) {
      throw error
    }
    throw createError({
      statusCode: 500,
      statusMessage: 'Fehler bei der Newsletter-Anmeldung'
    })
  }
})

async function sendConfirmationEmail(email, name, token, groupName) {
  const smtpUser = process.env.SMTP_USER
  const smtpPass = process.env.SMTP_PASS
  
  if (!smtpUser || !smtpPass) {
    console.warn('SMTP-Credentials fehlen! Bestätigungsmail kann nicht gesendet werden.')
    return
  }

  const baseUrl = process.env.NUXT_PUBLIC_BASE_URL || 'http://localhost:3100'
  const confirmationUrl = `${baseUrl}/newsletter/confirm?token=${token}`

  const transporter = nodemailer.createTransport({
    host: process.env.SMTP_HOST || 'smtp.gmail.com',
    port: process.env.SMTP_PORT || 587,
    secure: false,
    auth: {
      user: smtpUser,
      pass: smtpPass
    }
  })

  await transporter.sendMail({
    from: process.env.SMTP_FROM || 'noreply@harheimertc.de',
    to: email,
    subject: `Newsletter-Anmeldung bestätigen - ${groupName} - Harheimer TC`,
    html: `
      <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
        <h2 style="color: #dc2626;">Newsletter-Anmeldung bestätigen</h2>
        <p>Hallo ${name || 'Liebe/r Abonnent/in'},</p>
        <p>vielen Dank für Ihre Anmeldung zum Newsletter "${groupName}" des Harheimer TC!</p>
        <p>Bitte bestätigen Sie Ihre Anmeldung, indem Sie auf den folgenden Link klicken:</p>
        <p style="margin: 30px 0;">
          <a href="${confirmationUrl}" style="display: inline-block; padding: 12px 24px; background-color: #dc2626; color: white; text-decoration: none; border-radius: 5px;">
            Newsletter-Anmeldung bestätigen
          </a>
        </p>
        <p>Falls Sie sich nicht angemeldet haben, können Sie diese E-Mail ignorieren.</p>
        <p style="margin-top: 30px; color: #666; font-size: 12px;">
          Mit sportlichen Grüßen,<br>
          Ihr Harheimer Tischtennis-Club 1954 e.V.
        </p>
      </div>
    `
  })
}

