defmodule Berrypod.Newsletter.Notifier do
  @moduledoc """
  Email delivery for newsletter confirmation and campaigns.

  Sends multipart emails (HTML + plain text fallback) wrapped in a
  simple branded template with the shop name and unsubscribe footer.
  """

  import Swoosh.Email

  alias Berrypod.Mailer

  require Logger

  @doc "Sends the double opt-in confirmation email."
  def deliver_confirmation(subscriber, raw_token) do
    shop_name = Berrypod.Settings.get_setting("shop_name", "Berrypod")
    confirm_url = BerrypodWeb.Endpoint.url() <> "/newsletter/confirm/" <> raw_token

    text = """
    Thanks for signing up to the #{shop_name} newsletter!

    Please confirm your email to start receiving updates:

    #{confirm_url}

    This link expires in 48 hours. If you didn't subscribe,
    just ignore this email and you won't hear from us.
    """

    html_content = """
    <p>Thanks for signing up to the #{esc(shop_name)} newsletter!</p>
    <p>Please confirm your email to start receiving updates:</p>
    <p style="margin: 24px 0;">
      <a href="#{esc(confirm_url)}" style="display: inline-block; padding: 12px 24px; background-color: #111827; color: #ffffff; text-decoration: none; border-radius: 6px; font-weight: 600;">Confirm subscription</a>
    </p>
    <p style="color: #6b7280; font-size: 14px;">This link expires in 48 hours. If you didn't subscribe, just ignore this email.</p>
    """

    html = wrap_html(shop_name, html_content)

    deliver(subscriber.email, "Confirm your subscription", text, html)
  end

  @doc "Sends a test/preview email of a campaign to the given address."
  def deliver_test(campaign, to_email) do
    shop_name = Berrypod.Settings.get_setting("shop_name", "Berrypod")
    sample_unsub = BerrypodWeb.Endpoint.url() <> "/unsubscribe/test-preview"

    body_with_url =
      String.replace(campaign.body, "{{unsubscribe_url}}", sample_unsub)

    text = """
    [TEST] #{body_with_url}

    ---
    This is a test email. No subscribers received this.
    """

    html_content = text_to_html(body_with_url, sample_unsub)
    html = wrap_html(shop_name, html_content, sample_unsub)

    deliver(to_email, "[Test] #{campaign.subject}", text, html)
  end

  @doc "Sends a campaign email to a single subscriber."
  def deliver_campaign(campaign, subscriber) do
    shop_name = Berrypod.Settings.get_setting("shop_name", "Berrypod")
    unsubscribe_url = build_unsubscribe_url(subscriber.email)

    body_with_url =
      String.replace(campaign.body, "{{unsubscribe_url}}", unsubscribe_url)

    text = """
    #{body_with_url}

    ---
    You're receiving this because you subscribed to the #{shop_name} newsletter.
    Unsubscribe: #{unsubscribe_url}
    """

    html_content = text_to_html(body_with_url, unsubscribe_url)
    html = wrap_html(shop_name, html_content, unsubscribe_url)

    email =
      new()
      |> to(subscriber.email)
      |> from({shop_name, from_address()})
      |> subject(campaign.subject)
      |> text_body(text)
      |> html_body(html)
      |> header("List-Unsubscribe", "<#{unsubscribe_url}>")
      |> header("List-Unsubscribe-Post", "List-Unsubscribe=One-Click")

    case Mailer.deliver(email) do
      {:ok, _metadata} = result ->
        result

      {:error, reason} = error ->
        Logger.warning("Newsletter send failed for #{subscriber.email}: #{inspect(reason)}")
        error
    end
  end

  defp deliver(recipient, subject, text, html) do
    shop_name = Berrypod.Settings.get_setting("shop_name", "Berrypod")

    email =
      new()
      |> to(recipient)
      |> from({shop_name, from_address()})
      |> subject(subject)
      |> text_body(text)
      |> html_body(html)

    case Mailer.deliver(email) do
      {:ok, _metadata} = result ->
        result

      {:error, reason} = error ->
        Logger.warning("Failed to send newsletter email to #{recipient}: #{inspect(reason)}")
        error
    end
  end

  # Converts plain text campaign body to HTML paragraphs.
  # Splits on blank lines for paragraphs, preserves single line breaks.
  @doc false
  def text_to_html(text, unsubscribe_url \\ nil) do
    text
    |> String.replace("{{unsubscribe_url}}", unsubscribe_url || "#")
    |> String.split(~r/\n{2,}/, trim: true)
    |> Enum.map(fn paragraph ->
      paragraph
      |> String.trim()
      |> esc()
      |> linkify()
      |> String.replace("\n", "<br>")
      |> then(&"<p>#{&1}</p>")
    end)
    |> Enum.join("\n")
  end

  # Wraps HTML content in a branded email template.
  # Keeps it simple: single column, logo/shop name header, optional unsubscribe footer.
  @doc false
  def wrap_html(shop_name, content, unsubscribe_url \\ nil) do
    logo_html = build_logo_html(shop_name)

    footer =
      if unsubscribe_url do
        """
        <p style="color: #9ca3af; font-size: 12px; margin-top: 32px; padding-top: 16px; border-top: 1px solid #e5e7eb;">
          You're receiving this because you subscribed to the #{esc(shop_name)} newsletter.<br>
          <a href="#{esc(unsubscribe_url)}" style="color: #9ca3af;">Unsubscribe</a>
        </p>
        """
      else
        ""
      end

    """
    <!DOCTYPE html>
    <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="x-apple-disable-message-reformatting">
      <title>#{esc(shop_name)}</title>
      <style>
        body, table, td { -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; }
        table { border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; }
        a { word-break: break-all; }
        @media only screen and (max-width: 620px) {
          .email-container { width: 100% !important; }
          .email-padding { padding: 16px !important; }
          .email-header { padding: 16px 16px 12px !important; }
        }
      </style>
      <!--[if mso]>
      <style>body { font-family: Arial, sans-serif; }</style>
      <![endif]-->
    </head>
    <body style="margin: 0; padding: 0; background-color: #f3f4f6; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif; word-break: break-word;">
      <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background-color: #f3f4f6;">
        <tr>
          <td align="center" style="padding: 32px 16px;">
            <!--[if mso]><table role="presentation" width="560" cellpadding="0" cellspacing="0"><tr><td><![endif]-->
            <table role="presentation" class="email-container" width="560" cellpadding="0" cellspacing="0" style="max-width: 560px; width: 100%; background-color: #ffffff; border-radius: 8px;">
              <tr>
                <td class="email-header" style="padding: 24px 32px 16px; border-bottom: 1px solid #e5e7eb;">
                  #{logo_html}
                </td>
              </tr>
              <tr>
                <td class="email-padding" style="padding: 24px 32px 32px; color: #374151; font-size: 16px; line-height: 1.6;">
                  #{content}
                  #{footer}
                </td>
              </tr>
            </table>
            <!--[if mso]></td></tr></table><![endif]-->
          </td>
        </tr>
      </table>
    </body>
    </html>
    """
  end

  # Builds the header logo/name HTML. Uses the shop logo if configured,
  # falls back to the favicon (served as PNG), or plain text.
  defp build_logo_html(shop_name) do
    base_url = BerrypodWeb.Endpoint.url()
    theme = Berrypod.Settings.get_theme_settings()

    cond do
      # Logo image configured and not SVG (email clients don't support SVG)
      theme.logo_image_id && !is_svg_image?(theme.logo_image_id) ->
        src = "#{base_url}/image_cache/#{theme.logo_image_id}.webp"
        height = theme.logo_size || 36

        ~s(<img src="#{esc(src)}" alt="#{esc(shop_name)}" height="#{height}" style="height: #{height}px; width: auto; display: block;">)

      # Favicon icon exists (served as PNG at /apple-touch-icon.png)
      has_favicon_icon?() ->
        src = "#{base_url}/apple-touch-icon.png"

        ~s(<img src="#{esc(src)}" alt="#{esc(shop_name)}" width="36" height="36" style="height: 36px; width: 36px; display: inline-block; vertical-align: middle; border-radius: 4px; margin-right: 8px;">) <>
          ~s(<strong style="font-size: 18px; color: #111827; vertical-align: middle;">#{esc(shop_name)}</strong>)

      # No image — text only
      true ->
        ~s(<strong style="font-size: 18px; color: #111827;">#{esc(shop_name)}</strong>)
    end
  end

  defp is_svg_image?(image_id) do
    case Berrypod.Repo.get(Berrypod.Media.Image, image_id) do
      %{is_svg: true} -> true
      _ -> false
    end
  end

  defp has_favicon_icon? do
    require Ecto.Query

    Berrypod.Repo.exists?(
      Ecto.Query.from(i in Berrypod.Media.Image, where: i.image_type == "icon")
    )
  end

  # Turns bare URLs in escaped text into clickable links.
  defp linkify(escaped_text) do
    Regex.replace(~r/(https?:\/\/[^\s<]+)/, escaped_text, fn url, _ ->
      ~s(<a href="#{url}" style="color: #2563eb;">#{url}</a>)
    end)
  end

  # HTML-escapes a string for safe embedding.
  defp esc(text) do
    text
    |> String.replace("&", "&amp;")
    |> String.replace("<", "&lt;")
    |> String.replace(">", "&gt;")
    |> String.replace("\"", "&quot;")
  end

  defp from_address do
    Berrypod.Settings.get_setting("email_from_address", "noreply@example.com")
  end

  defp build_unsubscribe_url(email) do
    token = Phoenix.Token.sign(BerrypodWeb.Endpoint, "email-unsub", email)
    BerrypodWeb.Endpoint.url() <> "/unsubscribe/" <> token
  end
end
