import { convert } from 'html-to-text'
import { CaminoMailMessage, MailjetPostMessageRecipient, mailJetSendMail } from './index'
import { EmailTemplateId } from './types'
import { emailCheck } from '../email-check'
import { config } from '../../config/index'
import { isNotNullNorUndefined, OmitDistributive, onlyUnique } from 'camino-common/src/typescript-tools'
import { Chunk, Effect, Stream } from 'effect'
import { callAndExit } from '../fp-tools'

const NOMBRE_DE_MAILS_EN_ENVOI_GROUPE = 49

export const mailjetSend = async (emails: readonly string[], message: OmitDistributive<CaminoMailMessage, 'To' | 'Bcc'>): Promise<void> => {
  if (!Array.isArray(emails)) {
    throw new Error(`un tableau d'emails est attendu ${emails}`)
  }

  emails.forEach(to => {
    if (!emailCheck(to)) {
      throw new Error(`adresse email invalide ${to}`)
    }
  })

  // si on est pas sur le serveur de prod
  // l'adresse email du destinataire est remplacée
  if (config().NODE_ENV !== 'production' || config().ENV !== 'prod') {
    await mailjetSendForTestsOnly([config().ADMIN_EMAIL], message)
  } else {
    await mailjetSendForTestsOnly(emails.filter(isNotNullNorUndefined).filter(onlyUnique), message)
  }
}
export const mailjetSendForTestsOnly = async (emails: readonly string[], message: OmitDistributive<CaminoMailMessage, 'To' | 'Bcc'>): Promise<void> => {
  try {
    const sendTo: MailjetPostMessageRecipient[] = emails.map(Email => ({ Email }))

    await callAndExit(
      Stream.runDrain(
        Stream.fromIterable(sendTo).pipe(
          Stream.grouped(NOMBRE_DE_MAILS_EN_ENVOI_GROUPE),
          Stream.flatMap(emailsChunk => {
            const emails = Chunk.toArray(emailsChunk)
            return Effect.tryPromise(async () => {
              const fullMessage: CaminoMailMessage = {
                ...message,
                ...(emails.length === 1 ? { To: emails } : { To: [{ Email: config().ADMIN_EMAIL }], Bcc: emails }),
              }
              await mailJetSendMail(fullMessage)
            })
          })
        )
      )
    )
  } catch (e: any) {
    console.error('erreur: emailsSend', e)
    throw new Error(e)
  }
}

export const emailsSend = async (emails: string[], subject: string, html: string): Promise<void> => {
  if (config().NODE_ENV !== 'production' || config().ENV !== 'prod') {
    html = `<p style="color: red">destinataire(s): ${emails.join(', ')} | env: ${config().ENV} | node: ${config().NODE_ENV}</p> ${html}`
  }

  return mailjetSend(emails, {
    Subject: `[Camino] ${subject}`,
    HTMLPart: html,
    TextPart: convert(html, {
      wordwrap: 130,
    }),
  })
}

export const emailsWithTemplateSend = async (emails: string[], templateId: EmailTemplateId, params: Record<string, string>): Promise<void> => {
  return mailjetSend(emails, {
    TemplateID: templateId,
    TemplateLanguage: true,
    Variables: params,
  })
}
