defmodule SimpleshopTheme.Stripe.Setup do
  @moduledoc """
  Handles Stripe account setup: key verification, automatic webhook
  endpoint creation, and teardown.
  """

  alias SimpleshopTheme.Settings
  alias SimpleshopTheme.Secrets

  require Logger

  @webhook_events ["checkout.session.completed", "checkout.session.expired"]

  @doc """
  Verifies a Stripe API key by making a lightweight Balance API call.
  """
  def verify_api_key(api_key) do
    case Stripe.Balance.retrieve(%{}, api_key: api_key) do
      {:ok, _balance} -> :ok
      {:error, %Stripe.Error{message: message}} -> {:error, message}
      {:error, _} -> {:error, "Could not connect to Stripe"}
    end
  end

  @doc """
  Full setup flow: verify key, store it, create webhook endpoint if possible.

  Returns:
  - `{:ok, :webhook_created}` — key valid, webhook auto-created (production)
  - `{:ok, :localhost}` — key valid, but URL is localhost so webhook skipped
  - `{:error, message}` — key invalid or setup failed
  """
  def connect(api_key) do
    with :ok <- verify_api_key(api_key) do
      Settings.put_secret("stripe_api_key", api_key)

      case maybe_create_webhook(api_key) do
        {:ok, result} ->
          Secrets.load_all()
          {:ok, result}

        {:error, reason} ->
          # Key is valid and stored, but webhook creation failed.
          # Still load the key so checkout works (webhooks can be set up manually).
          Secrets.load_all()
          {:error, reason}
      end
    end
  end

  @doc """
  Removes Stripe configuration and deletes the webhook endpoint from Stripe.
  """
  def disconnect do
    delete_existing_webhook()

    for key <- ["stripe_api_key", "stripe_signing_secret", "stripe_webhook_endpoint_id"] do
      Settings.delete_setting(key)
    end

    Application.delete_env(:stripity_stripe, :api_key)
    Application.delete_env(:stripity_stripe, :signing_secret)
    :ok
  end

  @doc """
  Saves a manually-provided webhook signing secret (for dev mode / Stripe CLI).
  """
  def save_signing_secret(signing_secret) do
    Settings.put_secret("stripe_signing_secret", signing_secret)
    Secrets.load_all()
  end

  @doc """
  Returns the webhook URL for this app.
  """
  def webhook_url do
    "#{SimpleshopThemeWeb.Endpoint.url()}/webhooks/stripe"
  end

  @doc """
  Returns true if the app is running on localhost (Stripe can't reach it).
  """
  def localhost? do
    url = SimpleshopThemeWeb.Endpoint.url()
    uri = URI.parse(url)
    uri.host in ["localhost", "127.0.0.1", "0.0.0.0", "::1"]
  end

  defp maybe_create_webhook(api_key) do
    if localhost?() do
      {:ok, :localhost}
    else
      delete_existing_webhook()
      create_webhook(api_key)
    end
  end

  defp create_webhook(api_key) do
    params = %{
      url: webhook_url(),
      enabled_events: @webhook_events
    }

    case Stripe.WebhookEndpoint.create(params, api_key: api_key) do
      {:ok, endpoint} ->
        Settings.put_secret("stripe_signing_secret", endpoint.secret)
        Settings.put_setting("stripe_webhook_endpoint_id", endpoint.id, "string")
        Logger.info("Stripe webhook endpoint created: #{endpoint.id}")
        {:ok, :webhook_created}

      {:error, %Stripe.Error{message: message}} ->
        Logger.warning("Failed to create Stripe webhook: #{message}")
        {:error, message}

      {:error, _} ->
        {:error, "Failed to create webhook endpoint"}
    end
  end

  defp delete_existing_webhook do
    endpoint_id = Settings.get_setting("stripe_webhook_endpoint_id")
    api_key = Settings.get_secret("stripe_api_key")

    if endpoint_id && api_key do
      case Stripe.WebhookEndpoint.delete(endpoint_id, api_key: api_key) do
        {:ok, _} ->
          Logger.info("Deleted Stripe webhook endpoint: #{endpoint_id}")

        {:error, reason} ->
          Logger.warning("Failed to delete webhook endpoint #{endpoint_id}: #{inspect(reason)}")
      end
    end
  end
end
