// src/lib/email/newsletter-service.ts

import type { Payload } from 'payload'
import type { NewsletterSubscriber, Tenant } from '../../payload-types'
import { sendTenantEmail } from './tenant-email-service'
import {
  getConfirmationEmailHtml,
  getConfirmationEmailText,
  getWelcomeEmailHtml,
  getWelcomeEmailText,
  getUnsubscribeEmailHtml,
  getUnsubscribeEmailText,
  type NewsletterTemplateData,
} from './newsletter-templates'

// Token-Gültigkeitsdauer: 48 Stunden
const TOKEN_EXPIRY_HOURS = 48
const UNSUBSCRIBE_TOKEN_EXPIRY_DAYS = 365

export interface SubscribeResult {
  success: boolean
  message: string
  subscriberId?: number
  alreadySubscribed?: boolean
  alreadyPending?: boolean
}

export interface ConfirmResult {
  success: boolean
  message: string
  email?: string
}

export interface UnsubscribeResult {
  success: boolean
  message: string
}

/**
 * Newsletter-Service für Double Opt-In
 */
export class NewsletterService {
  private payload: Payload
  private baseUrl: string

  constructor(payload: Payload) {
    this.payload = payload
    this.baseUrl = process.env.PAYLOAD_PUBLIC_SERVER_URL || 'https://pl.c2sgmbh.de'
  }

  /**
   * Newsletter-Anmeldung starten (sendet Double Opt-In E-Mail)
   */
  async subscribe(
    tenantId: number,
    data: {
      email: string
      firstName?: string
      lastName?: string
      interests?: ('general' | 'blog' | 'products' | 'offers' | 'events')[]
      source?: string
      ipAddress?: string
      userAgent?: string
    },
  ): Promise<SubscribeResult> {
    try {
      // Prüfen ob E-Mail bereits existiert für diesen Tenant
      const existing = await this.payload.find({
        collection: 'newsletter-subscribers',
        where: {
          and: [
            { email: { equals: data.email.toLowerCase() } },
            { tenant: { equals: tenantId } },
          ],
        },
        limit: 1,
      })

      if (existing.docs.length > 0) {
        const subscriber = existing.docs[0] as NewsletterSubscriber

        // Bereits bestätigt
        if (subscriber.status === 'confirmed') {
          return {
            success: true,
            message: 'Diese E-Mail-Adresse ist bereits für den Newsletter angemeldet.',
            alreadySubscribed: true,
          }
        }

        // Noch ausstehend - erneut E-Mail senden
        if (subscriber.status === 'pending') {
          // Token erneuern
          const newToken = crypto.randomUUID()
          await this.payload.update({
            collection: 'newsletter-subscribers',
            id: subscriber.id,
            data: {
              confirmationToken: newToken,
              subscribedAt: new Date().toISOString(),
            },
            overrideAccess: true,
            context: { skipNewsletterEmail: true }, // Hook soll keine E-Mail senden
          })

          // Double Opt-In E-Mail erneut senden
          await this.sendConfirmationEmail(tenantId, {
            ...subscriber,
            confirmationToken: newToken,
          } as NewsletterSubscriber)

          return {
            success: true,
            message: 'Eine neue Bestätigungs-E-Mail wurde gesendet.',
            subscriberId: subscriber.id,
            alreadyPending: true,
          }
        }

        // War abgemeldet - erneut anmelden
        if (subscriber.status === 'unsubscribed') {
          const newToken = crypto.randomUUID()
          await this.payload.update({
            collection: 'newsletter-subscribers',
            id: subscriber.id,
            data: {
              status: 'pending',
              confirmationToken: newToken,
              subscribedAt: new Date().toISOString(),
              confirmedAt: null,
              unsubscribedAt: null,
              firstName: data.firstName || subscriber.firstName,
              lastName: data.lastName || subscriber.lastName,
              interests: data.interests || subscriber.interests,
              source: data.source || subscriber.source,
            },
            overrideAccess: true,
            context: { skipNewsletterEmail: true }, // Hook soll keine E-Mail senden
          })

          await this.sendConfirmationEmail(tenantId, {
            ...subscriber,
            firstName: data.firstName || subscriber.firstName,
            confirmationToken: newToken,
          } as NewsletterSubscriber)

          return {
            success: true,
            message: 'Bitte bestätigen Sie Ihre E-Mail-Adresse über den zugesendeten Link.',
            subscriberId: subscriber.id,
          }
        }
      }

      // Neuen Subscriber erstellen
      const subscriber = await this.payload.create({
        collection: 'newsletter-subscribers',
        data: {
          email: data.email.toLowerCase(),
          firstName: data.firstName,
          lastName: data.lastName,
          interests: data.interests,
          source: data.source,
          ipAddress: data.ipAddress,
          userAgent: data.userAgent,
          status: 'pending',
          tenant: tenantId,
        },
        overrideAccess: true,
        context: { skipNewsletterEmail: true }, // Hook soll keine E-Mail senden, Service macht das
      })

      // Double Opt-In E-Mail senden
      await this.sendConfirmationEmail(tenantId, subscriber as NewsletterSubscriber)

      return {
        success: true,
        message: 'Bitte bestätigen Sie Ihre E-Mail-Adresse über den zugesendeten Link.',
        subscriberId: subscriber.id,
      }
    } catch (error) {
      console.error('[Newsletter] Subscribe error:', error)
      return {
        success: false,
        message: 'Ein Fehler ist aufgetreten. Bitte versuchen Sie es später erneut.',
      }
    }
  }

  /**
   * Newsletter-Anmeldung bestätigen
   */
  async confirmSubscription(token: string): Promise<ConfirmResult> {
    try {
      // Subscriber mit Token finden
      const result = await this.payload.find({
        collection: 'newsletter-subscribers',
        where: {
          confirmationToken: { equals: token },
        },
        limit: 1,
        depth: 1,
      })

      if (result.docs.length === 0) {
        return {
          success: false,
          message: 'Ungültiger oder abgelaufener Bestätigungs-Link.',
        }
      }

      const subscriber = result.docs[0] as NewsletterSubscriber

      // Bereits bestätigt
      if (subscriber.status === 'confirmed') {
        return {
          success: true,
          message: 'Ihre E-Mail-Adresse wurde bereits bestätigt.',
          email: subscriber.email,
        }
      }

      // Token-Ablauf prüfen (48 Stunden)
      if (subscriber.subscribedAt) {
        const subscribedAt = new Date(subscriber.subscribedAt)
        const expiryTime = new Date(subscribedAt.getTime() + TOKEN_EXPIRY_HOURS * 60 * 60 * 1000)

        if (new Date() > expiryTime) {
          return {
            success: false,
            message: 'Der Bestätigungs-Link ist abgelaufen. Bitte melden Sie sich erneut an.',
          }
        }
      }

      // Status auf bestätigt setzen und Token rotieren
      const unsubscribeToken = crypto.randomUUID()
      await this.payload.update({
        collection: 'newsletter-subscribers',
        id: subscriber.id,
        data: {
          status: 'confirmed',
          confirmedAt: new Date().toISOString(),
          confirmationToken: unsubscribeToken,
        },
        overrideAccess: true,
      })

      // Tenant-ID ermitteln
      const tenantId = typeof subscriber.tenant === 'object' && subscriber.tenant
        ? subscriber.tenant.id
        : subscriber.tenant

      // Willkommens-E-Mail senden
      if (tenantId) {
        await this.sendWelcomeEmail(
          tenantId as number,
          { ...subscriber, confirmationToken: unsubscribeToken } as NewsletterSubscriber,
        )
      }

      return {
        success: true,
        message: 'Vielen Dank! Ihre Newsletter-Anmeldung wurde erfolgreich bestätigt.',
        email: subscriber.email,
      }
    } catch (error) {
      console.error('[Newsletter] Confirm error:', error)
      return {
        success: false,
        message: 'Ein Fehler ist aufgetreten. Bitte versuchen Sie es später erneut.',
      }
    }
  }

  /**
   * Newsletter abbestellen
   */
  async unsubscribe(token: string): Promise<UnsubscribeResult> {
    try {
      // Subscriber ausschließlich per zufälligem Token finden
      let subscriber: NewsletterSubscriber | null = null

      const byToken = await this.payload.find({
        collection: 'newsletter-subscribers',
        where: {
          confirmationToken: { equals: token },
        },
        limit: 1,
        depth: 1,
      })

      if (byToken.docs.length > 0) {
        subscriber = byToken.docs[0] as NewsletterSubscriber
      }

      if (!subscriber) {
        return {
          success: false,
          message: 'Abonnement nicht gefunden.',
        }
      }

      // Bereits abgemeldet
      if (subscriber.status === 'unsubscribed') {
        return {
          success: true,
          message: 'Sie sind bereits vom Newsletter abgemeldet.',
        }
      }

      if (subscriber.status === 'confirmed' && subscriber.confirmedAt) {
        const confirmedAt = new Date(subscriber.confirmedAt)
        const expiresAt = new Date(
          confirmedAt.getTime() + UNSUBSCRIBE_TOKEN_EXPIRY_DAYS * 24 * 60 * 60 * 1000,
        )

        if (new Date() > expiresAt) {
          return {
            success: false,
            message: 'Der Abmelde-Link ist abgelaufen. Bitte fordern Sie einen neuen Link an.',
          }
        }
      }

      // Tenant-ID ermitteln
      const tenantId = typeof subscriber.tenant === 'object' && subscriber.tenant
        ? subscriber.tenant.id
        : subscriber.tenant

      // Status auf abgemeldet setzen
      await this.payload.update({
        collection: 'newsletter-subscribers',
        id: subscriber.id,
        data: {
          status: 'unsubscribed',
          unsubscribedAt: new Date().toISOString(),
          confirmationToken: crypto.randomUUID(),
        },
        overrideAccess: true,
      })

      // Abmelde-Bestätigung senden
      await this.sendUnsubscribeEmail(tenantId as number, subscriber)

      return {
        success: true,
        message: 'Sie wurden erfolgreich vom Newsletter abgemeldet.',
      }
    } catch (error) {
      console.error('[Newsletter] Unsubscribe error:', error)
      return {
        success: false,
        message: 'Ein Fehler ist aufgetreten. Bitte versuchen Sie es später erneut.',
      }
    }
  }

  /**
   * Double Opt-In Bestätigungs-E-Mail senden
   */
  private async sendConfirmationEmail(
    tenantId: number,
    subscriber: NewsletterSubscriber,
  ): Promise<void> {
    const tenant = await this.getTenant(tenantId)
    const templateData = this.buildTemplateData(tenant, subscriber)

    await sendTenantEmail(this.payload, tenantId, {
      to: subscriber.email,
      subject: `Newsletter-Anmeldung bestätigen - ${tenant.name}`,
      html: getConfirmationEmailHtml(templateData),
      text: getConfirmationEmailText(templateData),
      source: 'newsletter',
      metadata: {
        type: 'double-opt-in',
        subscriberId: subscriber.id,
      },
    })
  }

  /**
   * Willkommens-E-Mail nach erfolgreicher Bestätigung senden.
   */
  private async sendWelcomeEmail(
    tenantId: number,
    subscriber: NewsletterSubscriber,
  ): Promise<void> {
    const tenant = await this.getTenant(tenantId)
    const templateData = this.buildTemplateData(tenant, subscriber)

    await sendTenantEmail(this.payload, tenantId, {
      to: subscriber.email,
      subject: `Willkommen beim Newsletter - ${tenant.name}`,
      html: getWelcomeEmailHtml(templateData),
      text: getWelcomeEmailText(templateData),
      source: 'newsletter',
      metadata: {
        type: 'welcome',
        subscriberId: subscriber.id,
      },
    })
  }

  /**
   * Abmelde-Bestätigung senden.
   */
  private async sendUnsubscribeEmail(
    tenantId: number,
    subscriber: NewsletterSubscriber,
  ): Promise<void> {
    const tenant = await this.getTenant(tenantId)
    const templateData = this.buildTemplateData(tenant, subscriber)

    await sendTenantEmail(this.payload, tenantId, {
      to: subscriber.email,
      subject: `Newsletter-Abmeldung bestätigt - ${tenant.name}`,
      html: getUnsubscribeEmailHtml(templateData),
      text: getUnsubscribeEmailText(templateData),
      source: 'newsletter',
      metadata: {
        type: 'unsubscribe-confirmation',
        subscriberId: subscriber.id,
      },
    })
  }

  /**
   * Tenant laden
   */
  private async getTenant(tenantId: number): Promise<Tenant> {
    const tenant = await this.payload.findByID({
      collection: 'tenants',
      id: tenantId,
      depth: 0,
    })
    return tenant as Tenant
  }

  /**
   * Template-Daten zusammenstellen
   *
   * Für Confirmation- und Unsubscribe-Links wird ein zufälliger Token verwendet.
   */
  private buildTemplateData(
    tenant: Tenant,
    subscriber: NewsletterSubscriber,
  ): NewsletterTemplateData {
    // Tenant-Website URL ermitteln
    const tenantWebsite = tenant.domains?.[0]?.domain
      ? `https://${tenant.domains[0].domain}`
      : undefined

    // Privacy Policy URL
    const privacyPolicyUrl = tenantWebsite
      ? `${tenantWebsite}/datenschutz`
      : undefined

    const unsubscribeToken = subscriber.confirmationToken || ''

    return {
      firstName: subscriber.firstName || undefined,
      email: subscriber.email,
      confirmationUrl: `${this.baseUrl}/api/newsletter/confirm?token=${subscriber.confirmationToken}`,
      unsubscribeUrl: `${this.baseUrl}/api/newsletter/unsubscribe?token=${unsubscribeToken}`,
      tenantName: tenant.name,
      tenantWebsite,
      privacyPolicyUrl,
    }
  }
}

/**
 * Factory-Funktion für Newsletter-Service
 */
export function createNewsletterService(payload: Payload): NewsletterService {
  return new NewsletterService(payload)
}
