defmodule Berrypod.KeyValidation do
  @moduledoc """
  Lightweight format validation for API keys.

  Auto-strips whitespace and checks known formats before attempting
  network calls, giving users helpful error messages instead of
  cryptic "connection failed" responses.

  All functions return `{:ok, trimmed_key}` or `{:error, message}`.
  """

  @doc """
  Validates a Stripe secret key.

  Checks for the `sk_test_` or `sk_live_` prefix. Detects common
  mistakes like pasting a publishable key or restricted key.
  """
  def validate_stripe_key(key) do
    key = trim(key)

    cond do
      key == "" ->
        {:error, "Please enter your Stripe secret key"}

      String.starts_with?(key, "pk_") ->
        {:error,
         "This looks like a publishable key (starts with pk_). You need the secret key, which starts with sk_test_ or sk_live_"}

      String.starts_with?(key, "rk_") ->
        {:error,
         "This looks like a restricted key (starts with rk_). You need the secret key, which starts with sk_test_ or sk_live_"}

      not String.starts_with?(key, "sk_test_") and not String.starts_with?(key, "sk_live_") ->
        {:error,
         "Stripe secret keys start with sk_test_ or sk_live_. Check you're copying the right key from the Stripe dashboard"}

      String.length(key) < 20 ->
        {:error, "This key looks too short. Check you copied the full key from Stripe"}

      true ->
        {:ok, key}
    end
  end

  @doc """
  Validates a print provider API key (Printify, Printful, etc.).

  Checks known formats for each provider:
  - Printify: 36-character UUID format
  - Printful: typically 40+ characters
  """
  def validate_provider_key(key, provider_type \\ nil) do
    key = trim(key)

    cond do
      key == "" ->
        {:error, "Please enter your API token"}

      String.length(key) < 10 ->
        {:error, "This looks too short for an API token. Check you copied the full value"}

      true ->
        validate_provider_format(key, provider_type)
    end
  end

  # Printify uses 36-character UUID format
  defp validate_provider_format(key, "printify") do
    # UUID format: 8-4-4-4-12 with hyphens = 36 chars
    cond do
      String.length(key) == 36 and uuid_format?(key) ->
        {:ok, key}

      String.length(key) < 32 ->
        {:error,
         "This looks too short — Printify API keys are 36 characters. Find yours at Settings → Connections"}

      String.length(key) > 40 ->
        {:error,
         "This looks too long — Printify API keys are 36 characters. Make sure you're copying just the API key"}

      not uuid_format?(key) and String.length(key) in 32..40 ->
        # Close enough in length but wrong format - might be missing hyphens
        {:error,
         "Printify API keys are in UUID format (like xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx). Check you copied the full key"}

      true ->
        {:ok, key}
    end
  end

  # Printful tokens are typically longer OAuth-style tokens
  defp validate_provider_format(key, "printful") do
    cond do
      String.length(key) < 20 ->
        {:error, "This looks too short for a Printful token. Find yours at Settings → API Access"}

      true ->
        {:ok, key}
    end
  end

  # Unknown provider - basic validation
  defp validate_provider_format(key, _provider_type), do: {:ok, key}

  # Check if string matches UUID format (8-4-4-4-12 hex with hyphens)
  defp uuid_format?(key) do
    String.match?(
      key,
      ~r/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/
    )
  end

  @doc """
  Validates an email provider API key or secret.

  Checks format for providers with known key patterns.
  Falls through to basic validation for unknown providers.
  """
  def validate_email_key(key, adapter_key, field_key) do
    key = trim(key)

    if key == "" do
      {:error, "Please enter your API key"}
    else
      validate_email_format(key, adapter_key, field_key)
    end
  end

  # ── Email provider format checks ──

  # Known prefixes for cross-provider detection
  @known_prefixes [
    {"SG.", "SendGrid"},
    {"xkeysib-", "Brevo"},
    {"mlsn.", "MailerSend"}
  ]

  # SendGrid: SG.{id}.{secret}
  defp validate_email_format(key, "sendgrid", "api_key") do
    cond do
      String.starts_with?(key, "SG.") -> {:ok, key}
      wrong = wrong_provider_hint(key, "sendgrid") -> {:error, wrong}
      true -> {:error, "SendGrid API keys start with SG. — find yours in Settings → API Keys"}
    end
  end

  # Brevo: xkeysib- prefix
  defp validate_email_format(key, "brevo", "api_key") do
    cond do
      String.starts_with?(key, "xkeysib-") ->
        {:ok, key}

      wrong = wrong_provider_hint(key, "brevo") ->
        {:error, wrong}

      true ->
        {:error,
         "Brevo API keys start with xkeysib- — find yours under SMTP & API in your Brevo account"}
    end
  end

  # Mailjet: api_key and secret are both 32-char alphanumeric
  defp validate_email_format(key, "mailjet", "api_key") do
    cond do
      String.length(key) >= 20 ->
        {:ok, key}

      wrong = wrong_provider_hint(key, "mailjet") ->
        {:error, wrong}

      true ->
        {:error,
         "This looks too short for a Mailjet API key — find yours under API Key Management in your Mailjet account"}
    end
  end

  defp validate_email_format(key, "mailjet", "secret") do
    cond do
      String.length(key) >= 20 ->
        {:ok, key}

      wrong = wrong_provider_hint(key, "mailjet") ->
        {:error, wrong}

      true ->
        {:error,
         "This looks too short for a Mailjet secret key — it's shown alongside your API key in API Key Management"}
    end
  end

  # MailerSend: mlsn. prefix
  defp validate_email_format(key, "mailersend", "api_key") do
    cond do
      String.starts_with?(key, "mlsn.") ->
        {:ok, key}

      String.length(key) >= 40 ->
        {:ok, key}

      wrong = wrong_provider_hint(key, "mailersend") ->
        {:error, wrong}

      true ->
        {:error,
         "MailerSend API tokens usually start with mlsn. — generate one under Domains → Manage → API Tokens"}
    end
  end

  # Non-api_key fields (domain, relay, base_url, etc.), basic checks
  defp validate_email_format(key, _adapter_key, _field_key) do
    if String.length(key) < 3 do
      {:error, "This value looks too short"}
    else
      {:ok, key}
    end
  end

  # Detects when a key meant for another provider is pasted into the wrong field
  defp wrong_provider_hint(key, current_adapter) do
    Enum.find_value(@known_prefixes, fn {prefix, name} ->
      if String.starts_with?(key, prefix) and current_adapter != String.downcase(name) do
        "This looks like a #{name} key, not the right one for this provider"
      end
    end)
  end

  # ── Helpers ──

  defp trim(nil), do: ""
  defp trim(key) when is_binary(key), do: String.trim(key)
end
