defmodule BerrypodWeb.Admin.EmailSettingsTest do
  use BerrypodWeb.ConnCase, async: false

  import Phoenix.LiveViewTest
  import Berrypod.AccountsFixtures

  alias Berrypod.{Mailer, Settings}

  setup do
    # Ensure mailer starts as test adapter and restore on exit
    original = Application.get_env(:berrypod, Berrypod.Mailer)
    Application.put_env(:berrypod, Berrypod.Mailer, adapter: Swoosh.Adapters.Test)

    on_exit(fn ->
      Application.put_env(:berrypod, Berrypod.Mailer, original)
    end)

    user = user_fixture()
    %{user: user}
  end

  describe "authenticated" do
    setup %{conn: conn, user: user} do
      conn = log_in_user(conn, user)
      %{conn: conn}
    end

    test "renders email settings page with provider cards", %{conn: conn} do
      {:ok, _view, html} = live(conn, ~p"/admin/settings/email")

      assert html =~ "Email settings"
      assert html =~ "Choose a provider"
      # Provider names rendered as radio cards
      assert html =~ "Brevo"
      assert html =~ "Mailjet"
      assert html =~ "Postal"
    end

    test "shows providers and advanced section", %{conn: conn} do
      {:ok, _view, html} = live(conn, ~p"/admin/settings/email")

      assert html =~ "Brevo"
      assert html =~ "SendGrid"
      assert html =~ "Mailjet"
      assert html =~ "MailerSend"

      # Advanced in details
      assert html =~ "Already have your own email server?"
      assert html =~ "SMTP"
      assert html =~ "Postal"
    end

    test "shows setup guidance", %{conn: conn} do
      {:ok, _view, html} = live(conn, ~p"/admin/settings/email")

      assert html =~ "needs an email provider"
    end

    test "renders all adapter field sections in the form", %{conn: conn} do
      {:ok, _view, html} = live(conn, ~p"/admin/settings/email")

      # All adapters have their config sections rendered (CSS controls visibility)
      assert html =~ ~s(data-adapter="brevo")
      assert html =~ ~s(data-adapter="sendgrid")
      assert html =~ ~s(data-adapter="mailjet")
      assert html =~ ~s(data-adapter="smtp")
      assert html =~ ~s(data-adapter="postal")
    end

    test "selecting a provider updates via phx-change", %{conn: conn} do
      {:ok, view, _html} = live(conn, ~p"/admin/settings/email")

      # Select SMTP via form change (radio inputs fire phx-change)
      html =
        view
        |> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "smtp"}})
        |> render_change()

      # SMTP fields are always rendered; check the step title changes
      assert html =~ "Server host"
      assert html =~ "Port"
    end

    test "saving config persists settings", %{conn: conn} do
      {:ok, view, _html} = live(conn, ~p"/admin/settings/email")

      # Select Brevo via form change
      view
      |> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "brevo"}})
      |> render_change()

      # Submit with namespaced fields: email[brevo][api_key]
      html =
        view
        |> form("form[phx-submit=\"save\"]", %{
          email: %{adapter: "brevo", brevo: %{api_key: "xkeysib-abc123def456"}}
        })
        |> render_submit()

      assert html =~ "Now send a test email"
      assert Settings.get_setting("email_adapter") == "brevo"
    end

    test "saving without required fields shows error", %{conn: conn} do
      {:ok, view, _html} = live(conn, ~p"/admin/settings/email")

      # Select Brevo
      view
      |> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "brevo"}})
      |> render_change()

      # Submit without API key
      html =
        view
        |> form("form[phx-submit=\"save\"]", %{
          email: %{adapter: "brevo", brevo: %{api_key: ""}}
        })
        |> render_submit()

      assert html =~ "API key is required"
    end

    test "saving with invalid port shows error", %{conn: conn} do
      {:ok, view, _html} = live(conn, ~p"/admin/settings/email")

      view
      |> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "smtp"}})
      |> render_change()

      html =
        view
        |> form("form[phx-submit=\"save\"]", %{
          email: %{adapter: "smtp", smtp: %{relay: "smtp.example.com", port: "abc"}}
        })
        |> render_submit()

      assert html =~ "must be a number"
    end

    test "shows test email section when configured", %{conn: conn} do
      Settings.put_setting("email_adapter", "brevo")
      Settings.put_secret("email_brevo_api_key", "xkeysib-test-abc")

      {:ok, _view, html} = live(conn, ~p"/admin/settings/email")

      assert html =~ "Send a test email"
      assert html =~ "Send test email"
    end

    test "hides test email section when not configured", %{conn: conn} do
      # Ensure clean state — no adapter configured
      Settings.delete_setting("email_adapter")
      Application.put_env(:berrypod, Berrypod.Mailer, adapter: Swoosh.Adapters.Local)

      {:ok, _view, html} = live(conn, ~p"/admin/settings/email")

      refute html =~ "Send test email"
    end

    test "sending test email shows success and sets verified flag", %{conn: conn} do
      Settings.put_setting("email_adapter", "brevo")
      Settings.put_secret("email_brevo_api_key", "xkeysib-test-abc")

      {:ok, view, _html} = live(conn, ~p"/admin/settings/email")

      # send_test is now async — click triggers the event, then handle_info completes it
      render_click(view, "send_test")
      # Wait for the async handle_info to complete
      html = render(view)

      assert html =~ "Email is working"
      assert html =~ "Send again"
      assert Mailer.email_verified?()
    end

    test "switching provider clears old provider settings", %{conn: conn} do
      # Save Mailjet config first
      Settings.put_setting("email_adapter", "mailjet")
      Settings.put_secret("email_mailjet_api_key", "mj-key-123")
      Settings.put_secret("email_mailjet_secret", "mj-secret-456")

      {:ok, view, _html} = live(conn, ~p"/admin/settings/email")

      # Switch to Brevo and save (namespaced fields)
      view
      |> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "brevo"}})
      |> render_change()

      view
      |> form("form[phx-submit=\"save\"]", %{
        email: %{adapter: "brevo", brevo: %{api_key: "xkeysib-switch-test"}}
      })
      |> render_submit()

      # Old Mailjet settings should be deleted
      assert Settings.get_setting("email_adapter") == "brevo"
      refute Settings.has_secret?("email_mailjet_api_key")
      refute Settings.has_secret?("email_mailjet_secret")
      # New Brevo key should exist
      assert Settings.has_secret?("email_brevo_api_key")
    end

    test "saving config clears verified flag", %{conn: conn} do
      Mailer.mark_email_verified()
      assert Mailer.email_verified?()

      {:ok, view, _html} = live(conn, ~p"/admin/settings/email")

      view
      |> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "brevo"}})
      |> render_change()

      view
      |> form("form[phx-submit=\"save\"]", %{
        email: %{adapter: "brevo", brevo: %{api_key: "xkeysib-def789ghi012"}}
      })
      |> render_submit()

      refute Mailer.email_verified?()
    end

    test "phx-change is no-op when adapter hasn't changed", %{conn: conn} do
      {:ok, view, _html} = live(conn, ~p"/admin/settings/email")

      # Select Brevo
      view
      |> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "brevo"}})
      |> render_change()

      # Trigger another change with the same adapter (simulates text field input)
      html =
        view
        |> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "brevo"}})
        |> render_change()

      # Should still show Brevo config
      assert html =~ "Brevo"
      assert html =~ "API key"
    end

    test "from_checklist param shows checklist banner", %{conn: conn} do
      {:ok, _view, html} = live(conn, ~p"/admin/settings/email?from=checklist")

      assert html =~ "setting up email"
      assert html =~ "Back to checklist"
    end

    test "has fieldset legend for accessibility", %{conn: conn} do
      {:ok, _view, html} = live(conn, ~p"/admin/settings/email")

      assert html =~ "Email provider"
      assert html =~ "sr-only"
    end

    test "only selected adapter config is open (details element)", %{conn: conn} do
      {:ok, view, _html} = live(conn, ~p"/admin/settings/email")

      # Select SMTP
      view
      |> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "smtp"}})
      |> render_change()

      # SMTP details should be open
      assert has_element?(view, ~s(details[data-adapter="smtp"][open]))
      # Others should not be open
      refute has_element?(view, ~s(details[data-adapter="brevo"][open]))
      refute has_element?(view, ~s(details[data-adapter="sendgrid"][open]))
      refute has_element?(view, ~s(details[data-adapter="postal"][open]))
    end
  end

  describe "unauthenticated" do
    test "redirects to login", %{conn: conn} do
      {:error, redirect} = live(conn, ~p"/admin/settings/email")
      assert {:redirect, %{to: path}} = redirect
      assert path == ~p"/users/log-in"
    end
  end
end
