defmodule BerrypodWeb.Admin.EmailSettings do
  use BerrypodWeb, :live_view

  alias Berrypod.Mailer
  alias Berrypod.Mailer.Adapters
  alias Berrypod.Settings

  @impl true
  def mount(_params, _session, socket) do
    env_locked = Mailer.env_var_configured?()
    {current_adapter, current_values} = Mailer.current_config()
    saved_adapter = Settings.get_setting("email_adapter")

    adapter_key = current_adapter || saved_adapter

    {:ok,
     socket
     |> assign(:page_title, "Email settings")
     |> assign(:env_locked, env_locked)
     |> assign(:adapter_key, adapter_key)
     |> assign(:current_values, current_values)
     |> assign(:all_adapters, Adapters.all())
     |> assign(:provider_options, provider_options())
     |> assign(:email_configured, Mailer.email_configured?())
     |> assign(
       :from_address,
       Settings.get_setting("email_from_address") || socket.assigns.current_scope.user.email
     )
     |> assign(:sending_test, false)
     |> assign(:from_checklist, false)
     |> assign(:form, to_form(%{}, as: :email))}
  end

  @impl true
  def handle_params(params, _uri, socket) do
    {:noreply, assign(socket, :from_checklist, params["from"] == "checklist")}
  end

  defp load_adapter_values(adapter_key) do
    case Adapters.get(adapter_key) do
      nil ->
        %{}

      adapter_info ->
        for field <- adapter_info.fields, into: %{} do
          settings_key = Adapters.settings_key(adapter_key, field.key)

          value =
            case field.type do
              :secret -> Settings.secret_hint(settings_key)
              _ -> Settings.get_setting(settings_key)
            end

          {field.key, value}
        end
    end
  end

  defp provider_options do
    Enum.map(Adapters.all(), fn adapter ->
      %{
        value: adapter.key,
        name: adapter.name,
        description: adapter.description,
        tags: adapter.tags,
        url: adapter.url
      }
    end)
  end

  @impl true
  def handle_event("change_adapter", %{"email" => %{"adapter" => key}}, socket) do
    values = load_adapter_values(key)
    {:noreply, socket |> assign(:adapter_key, key) |> assign(:current_values, values)}
  end

  def handle_event("save", %{"email" => params}, socket) do
    if socket.assigns.env_locked do
      {:noreply, put_flash(socket, :error, "Email config is controlled by environment variables")}
    else
      adapter_key = params["adapter"]
      adapter_info = Adapters.get(adapter_key)

      if adapter_info do
        save_adapter_config(socket, adapter_info, params)
      else
        {:noreply, put_flash(socket, :error, "Please select an email provider")}
      end
    end
  end

  def handle_event("disconnect", _params, socket) do
    if socket.assigns.env_locked do
      {:noreply, put_flash(socket, :error, "Email config is controlled by environment variables")}
    else
      # Clear all email settings
      Settings.delete_setting("email_adapter")

      for key <- Adapters.all_field_keys() do
        Settings.delete_setting(key)
      end

      Mailer.clear_email_verified()

      # Reset to Local adapter
      Application.put_env(:berrypod, Mailer, adapter: Swoosh.Adapters.Local)

      {:noreply,
       socket
       |> assign(:adapter_key, nil)
       |> assign(:current_values, %{})
       |> assign(:email_configured, false)
       |> put_flash(:info, "Email provider disconnected")}
    end
  end

  def handle_event("send_test", _params, socket) do
    user = socket.assigns.current_scope.user

    socket = assign(socket, :sending_test, true)

    case Mailer.send_test_email(user.email, socket.assigns.from_address) do
      {:ok, _} ->
        Mailer.mark_email_verified()

        {:noreply,
         socket
         |> assign(:sending_test, false)
         |> put_flash(:info, "Test email sent to #{user.email}")}

      {:error, reason} ->
        {:noreply,
         socket
         |> assign(:sending_test, false)
         |> put_flash(:error, "Failed to send test email: #{inspect(reason)}")}
    end
  end

  defp save_adapter_config(socket, adapter_info, params) do
    # Validate required fields
    missing =
      adapter_info.fields
      |> Enum.filter(& &1.required)
      |> Enum.filter(fn field ->
        val = params[field.key]
        empty = is_nil(val) or val == ""
        settings_key = Adapters.settings_key(adapter_info.key, field.key)
        # Secret fields can be left blank to keep existing value
        empty and not (field.type == :secret and Settings.get_secret(settings_key) != nil)
      end)

    if missing != [] do
      labels = Enum.map_join(missing, ", ", & &1.label)
      {:noreply, put_flash(socket, :error, "Missing required fields: #{labels}")}
    else
      # Save adapter type
      Settings.put_setting("email_adapter", adapter_info.key)

      # Save current adapter fields (blank secrets keep existing value)
      for field <- adapter_info.fields do
        value = params[field.key]
        settings_key = Adapters.settings_key(adapter_info.key, field.key)

        cond do
          value && value != "" ->
            case field.type do
              :secret -> Settings.put_secret(settings_key, value)
              :integer -> Settings.put_setting(settings_key, String.to_integer(value), "integer")
              _ -> Settings.put_setting(settings_key, value)
            end

          field.type == :secret ->
            :keep

          true ->
            Settings.delete_setting(settings_key)
        end
      end

      # Save from address
      from_address = params["from_address"] || ""

      if from_address != "" do
        Settings.put_setting("email_from_address", from_address)
      end

      # Config changed — require re-verification
      Mailer.clear_email_verified()

      # Apply config immediately
      Mailer.load_config()

      # Re-read current state
      {current_adapter, current_values} = Mailer.current_config()

      {:noreply,
       socket
       |> assign(:adapter_key, current_adapter)
       |> assign(:current_values, current_values)
       |> assign(:from_address, from_address)
       |> assign(:email_configured, Mailer.email_configured?())
       |> put_flash(:info, "Email settings saved")}
    end
  end

  @impl true
  def render(assigns) do
    ~H"""
    <div class="admin-content-medium">
      <div :if={@from_checklist} class="admin-checklist-banner">
        <.icon name="hero-clipboard-document-check" class="size-5 admin-checklist-banner-icon" />
        <span class="admin-checklist-banner-text">
          You're setting up email for your shop.
        </span>
        <.link navigate={~p"/admin"} class="admin-link admin-checklist-banner-link">
          &larr; Back to checklist
        </.link>
      </div>
      <.header>
        Email settings
        <:subtitle>
          Configure how your shop sends email. <strong>Transactional</strong>
          providers only handle order confirmations and password resets. <strong>All email</strong>
          providers also support newsletters and marketing campaigns.
        </:subtitle>
      </.header>

      <%= if @env_locked do %>
        <div class="admin-callout-warning">
          <div class="admin-callout-warning-body">
            <span class="admin-callout-warning-icon">
              <.icon name="hero-lock-closed" class="size-5" />
            </span>
            <div>
              <p class="admin-callout-warning-title">
                Controlled by environment variables
              </p>
              <p class="admin-callout-warning-desc">
                Email is configured via <code>SMTP_HOST</code> and related env vars.
                Remove them to configure email from this page instead.
              </p>
            </div>
          </div>
        </div>
      <% end %>

      <section class="admin-section">
        <.form for={@form} phx-change="change_adapter" phx-submit="save">
          <div id="email-provider-cards" phx-hook="CardRadioScroll">
            <.card_radio_group
              name="email[adapter]"
              value={@adapter_key}
              legend="Email provider"
              options={@provider_options}
              disabled={@env_locked}
              display={:tags}
            />
          </div>

          <%= for adapter <- @all_adapters do %>
            <% selected = @adapter_key == adapter.key %>
            <div
              id={"adapter-config-#{adapter.key}"}
              class="admin-adapter-config"
              hidden={!selected}
              data-adapter={adapter.key}
            >
              <div>
                <h3 class="admin-section-subheading">
                  {adapter.name}
                  <a
                    :if={adapter.url}
                    href={adapter.url}
                    target="_blank"
                    rel="noopener"
                    class="admin-link-subtle admin-adapter-link"
                  >
                    &nearr;
                  </a>
                </h3>
                <p class="admin-section-desc">{adapter.description}</p>
              </div>
              <.input
                name="email[from_address]"
                value={@from_address}
                type="email"
                label="From address"
                placeholder="noreply@yourshop.com"
                disabled={!selected || @env_locked}
              />
              <%= for field <- adapter.fields do %>
                <.adapter_field_static
                  field_def={field}
                  value={if selected, do: @current_values[field.key]}
                  disabled={!selected || @env_locked}
                />
              <% end %>
              <%= unless @env_locked do %>
                <div class="admin-row admin-row-lg">
                  <.button phx-disable-with="Saving..." disabled={!selected}>
                    Save settings
                  </.button>
                  <%= if selected && @email_configured do %>
                    <button
                      type="button"
                      phx-click="disconnect"
                      data-confirm="Remove email configuration? Transactional emails will stop being sent."
                      class="admin-link-danger"
                    >
                      Disconnect
                    </button>
                  <% end %>
                </div>
              <% end %>
            </div>
          <% end %>
        </.form>
      </section>

      <%= if @email_configured do %>
        <section class="admin-section-bordered">
          <h2 class="admin-section-heading">Test email</h2>
          <p class="admin-help-text">
            Send a test email to <strong>{@current_scope.user.email}</strong>
            to verify delivery works.
          </p>
          <div class="admin-section-body">
            <button
              phx-click="send_test"
              disabled={@sending_test}
              class="admin-btn admin-btn-outline"
            >
              <.icon name="hero-paper-airplane" class="size-4" />
              {if @sending_test, do: "Sending...", else: "Send test email"}
            </button>
          </div>
        </section>
      <% end %>
    </div>
    """
  end

  attr :field_def, :map, required: true
  attr :value, :any, default: nil
  attr :disabled, :boolean, default: false

  defp adapter_field_static(%{field_def: %{type: :secret}} = assigns) do
    ~H"""
    <div>
      <.input
        name={"email[#{@field_def.key}]"}
        value=""
        type="password"
        label={@field_def.label}
        autocomplete="off"
        placeholder={if @value, do: @value, else: ""}
        required={@field_def.required && !@value}
        disabled={@disabled}
      />
      <%= if @value && !@disabled do %>
        <p class="admin-help-text">
          Current: <code>{@value}</code> — leave blank to keep existing value
        </p>
      <% end %>
    </div>
    """
  end

  defp adapter_field_static(%{field_def: %{type: :integer}} = assigns) do
    ~H"""
    <.input
      name={"email[#{@field_def.key}]"}
      value={@value || @field_def.default || ""}
      type="number"
      label={@field_def.label}
      required={@field_def.required}
      disabled={@disabled}
    />
    """
  end

  defp adapter_field_static(assigns) do
    ~H"""
    <.input
      name={"email[#{@field_def.key}]"}
      value={@value || @field_def.default || ""}
      type="text"
      label={@field_def.label}
      required={@field_def.required}
      disabled={@disabled}
    />
    """
  end
end
