import { Resend } from 'resend'
import twilio from 'twilio'
import admin from 'firebase-admin'
import { prisma } from '../lib/prisma'
import { redis } from '../lib/redis'
import { NotificationType, NotificationChannel } from '@rentaldrivego/database'
import {
  renderLocalizedEmailHtml,
  resolveNotificationLocale,
  resolveNotificationTemplate,
} from './notificationLocalizationService'
import type { NotificationTemplateVariables } from './notificationLocalizationService'

const resendApiKey =
  process.env.RESEND_API_KEY &&
  process.env.RESEND_API_KEY !== 're_...' &&
  process.env.RESEND_API_KEY.startsWith('re_')
    ? process.env.RESEND_API_KEY
    : null

const resend = resendApiKey ? new Resend(resendApiKey) : null

const emailFromAddress =
  process.env.EMAIL_FROM && process.env.EMAIL_FROM !== 'noreply@example.com'
    ? process.env.EMAIL_FROM
    : null

const emailFromName =
  process.env.EMAIL_FROM_NAME && process.env.EMAIL_FROM_NAME !== 'Example App'
    ? process.env.EMAIL_FROM_NAME
    : null

const smtpHost = process.env.MAIL_HOST
const smtpPort = Number(process.env.MAIL_PORT ?? 0)
const smtpUser = process.env.MAIL_USERNAME
const smtpPass = process.env.MAIL_PASSWORD
const smtpSecure =
  process.env.MAIL_SCHEME === 'smtps' ||
  process.env.MAIL_ENCRYPTION === 'ssl' ||
  smtpPort === 465

const smtpFromAddress =
  process.env.MAIL_FROM_ADDRESS && !process.env.MAIL_FROM_ADDRESS.includes('${')
    ? process.env.MAIL_FROM_ADDRESS
    : null

const smtpFromName =
  process.env.MAIL_FROM_NAME && !process.env.MAIL_FROM_NAME.includes('${')
    ? process.env.MAIL_FROM_NAME
    : null

type SmtpTransport = {
  sendMail(options: Record<string, unknown>): Promise<{ messageId?: string }>
}

let smtpTransport: SmtpTransport | null = null

if (smtpHost && smtpPort && smtpUser && smtpPass) {
  try {
    const nodemailer = require('nodemailer') as {
      createTransport(options: Record<string, unknown>): SmtpTransport
    }

    smtpTransport = nodemailer.createTransport({
      host: smtpHost,
      port: smtpPort,
      secure: smtpSecure,
      auth: {
        user: smtpUser,
        pass: smtpPass,
      },
    })
  } catch (err: any) {
    console.warn('[Notifications] SMTP transport unavailable:', err?.message ?? String(err))
  }
}

const twilioClient =
  process.env.TWILIO_ACCOUNT_SID &&
  process.env.TWILIO_AUTH_TOKEN &&
  process.env.TWILIO_ACCOUNT_SID !== 'AC...' &&
  process.env.TWILIO_AUTH_TOKEN !== 'your-twilio-auth-token'
    ? twilio(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN)
    : null

const firebasePrivateKey = process.env.FIREBASE_PRIVATE_KEY?.replace(/\\n/g, '\n')
const hasFirebaseConfig =
  !!process.env.FIREBASE_PROJECT_ID &&
  !!process.env.FIREBASE_CLIENT_EMAIL &&
  !!firebasePrivateKey &&
  !firebasePrivateKey.includes('BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY')

if (hasFirebaseConfig && !admin.apps.length) {
  try {
    admin.initializeApp({
      credential: admin.credential.cert({
        projectId: process.env.FIREBASE_PROJECT_ID,
        privateKey: firebasePrivateKey,
        clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
      }),
    })
  } catch (err: any) {
    console.warn('[Notifications] Firebase init skipped:', err.message)
  }
}

interface SendNotificationOptions {
  type: NotificationType
  title?: string
  body?: string
  data?: Record<string, unknown>
  companyId?: string
  employeeId?: string
  renterId?: string
  billingAccountId?: string
  email?: string
  phone?: string
  fcmToken?: string
  channels: NotificationChannel[]
  locale?: string
  templateKey?: string
  templateVariables?: NotificationTemplateVariables
}

function resolveSmtpReplyTo() {
  if (!process.env.MAIL_REPLY_TO_ADDRESS || process.env.MAIL_REPLY_TO_ADDRESS.includes('${')) {
    return undefined
  }

  if (process.env.MAIL_REPLY_TO_NAME && !process.env.MAIL_REPLY_TO_NAME.includes('${')) {
    return `${process.env.MAIL_REPLY_TO_NAME} <${process.env.MAIL_REPLY_TO_ADDRESS}>`
  }

  return process.env.MAIL_REPLY_TO_ADDRESS
}

async function sendEmailWithProviders(opts: {
  to: string
  subject: string
  html: string
  text: string
}) {
  const errors: string[] = []

  if (resend) {
    try {
      if (!emailFromAddress || !emailFromName) {
        throw new Error('Email sender identity is not configured')
      }

      const { data, error } = await resend.emails.send({
        from: `${emailFromName} <${emailFromAddress}>`,
        to: opts.to,
        subject: opts.subject,
        html: opts.html,
        text: opts.text,
      })

      if (error) {
        throw new Error(error.message)
      }

      return {
        provider: 'resend' as const,
        providerMessageId: data?.id ?? null,
      }
    } catch (err: any) {
      errors.push(`Resend: ${err?.message ?? String(err)}`)
      console.warn('[Notifications] Resend delivery failed, falling back if possible:', err?.message ?? String(err))
    }
  }

  if (smtpTransport) {
    try {
      if (!smtpFromAddress) {
        throw new Error('SMTP sender identity is not configured')
      }

      const info = await smtpTransport.sendMail({
        from: smtpFromName ? `${smtpFromName} <${smtpFromAddress}>` : smtpFromAddress,
        to: opts.to,
        subject: opts.subject,
        html: opts.html,
        text: opts.text,
        replyTo: resolveSmtpReplyTo(),
      })

      return {
        provider: 'smtp' as const,
        providerMessageId: info.messageId ?? null,
      }
    } catch (err: any) {
      errors.push(`SMTP: ${err?.message ?? String(err)}`)
    }
  }

  if (errors.length) {
    throw new Error(errors.join(' | '))
  }

  throw new Error('No email provider is configured')
}

export async function sendNotification(opts: SendNotificationOptions) {
  const results: Array<{ channel: NotificationChannel; success: boolean; error?: string }> = []
  const resolvedLocale = await resolveNotificationLocale({
    companyId: opts.companyId,
    employeeId: opts.employeeId,
    renterId: opts.renterId,
    billingAccountId: opts.billingAccountId,
    locale: opts.locale,
  })

  for (const channel of opts.channels) {
    try {
      const rendered = opts.templateKey
        ? await resolveNotificationTemplate({
            templateKey: opts.templateKey,
            channel,
            locale: resolvedLocale,
            variables: opts.templateVariables,
          })
        : null

      const title = rendered?.subject ?? opts.title
      const body = rendered?.body ?? opts.body

      if (!title || !body) {
        throw new Error(`Notification content is incomplete for channel ${channel}`)
      }

      const notification = await prisma.notification.create({
        data: {
          type: opts.type,
          title,
          body,
          data: (opts.data ?? {}) as any,
          channel,
          templateKey: rendered?.templateKey ?? opts.templateKey ?? null,
          locale: rendered?.locale ?? resolvedLocale,
          status: 'PENDING',
          companyId: opts.companyId ?? null,
          employeeId: opts.employeeId ?? null,
          renterId: opts.renterId ?? null,
        },
      })

      let providerMessageId: string | null = null
      let success = false

      if (channel === 'EMAIL' && opts.email) {
        const emailResult = await sendEmailWithProviders({
          to: opts.email,
          subject: title,
          html: renderLocalizedEmailHtml(body, rendered?.locale ?? resolvedLocale),
          text: body,
        })
        providerMessageId = emailResult.providerMessageId
        success = true
      }

      if (channel === 'SMS' && opts.phone) {
        if (!twilioClient) throw new Error('Twilio is not configured')
        const msg = await twilioClient.messages.create({
          body,
          from: process.env.TWILIO_PHONE_NUMBER!,
          to: opts.phone,
        })
        providerMessageId = msg.sid
        success = true
      }

      if (channel === 'WHATSAPP' && opts.phone) {
        if (!twilioClient) throw new Error('Twilio is not configured')
        const msg = await twilioClient.messages.create({
          body,
          from: `whatsapp:${process.env.TWILIO_WHATSAPP_NUMBER}`,
          to: `whatsapp:${opts.phone}`,
        })
        providerMessageId = msg.sid
        success = true
      }

      if (channel === 'PUSH' && opts.fcmToken) {
        if (!admin.apps.length) throw new Error('Firebase is not configured')
        const response = await admin.messaging().send({
          token: opts.fcmToken,
          notification: { title, body },
          data: Object.fromEntries(
            Object.entries(opts.data ?? {}).map(([k, v]) => [k, String(v)])
          ),
        })
        providerMessageId = response
        success = true
      }

      if (channel === 'IN_APP') {
        // Emit via Socket.io through Redis pub/sub
        const targetId = opts.employeeId ?? opts.renterId
        if (targetId) {
          await redis.publish(
            `notifications:${targetId}`,
            JSON.stringify({ ...notification, status: 'DELIVERED' })
          )
        }
        success = true
      }

      await prisma.notification.update({
        where: { id: notification.id },
        data: {
          status: success ? 'SENT' : 'FAILED',
          sentAt: success ? new Date() : null,
          providerMessageId,
        },
      })

      results.push({ channel, success })
    } catch (err: any) {
      results.push({ channel, success: false, error: err.message })
    }
  }

  return results
}

export async function sendTransactionalEmail(opts: {
  to: string
  subject: string
  html: string
  text: string
}) {
  await sendEmailWithProviders(opts)
}
