defmodule SimpleshopThemeWeb.Admin.Providers.Form do
  use SimpleshopThemeWeb, :live_view

  alias SimpleshopTheme.Products
  alias SimpleshopTheme.Products.ProviderConnection
  alias SimpleshopTheme.Providers

  @impl true
  def mount(params, _session, socket) do
    {:ok, apply_action(socket, socket.assigns.live_action, params)}
  end

  defp apply_action(socket, :new, _params) do
    socket
    |> assign(:page_title, "Connect to Printify")
    |> assign(:connection, %ProviderConnection{provider_type: "printify"})
    |> assign(:form, to_form(ProviderConnection.changeset(%ProviderConnection{}, %{})))
    |> assign(:testing, false)
    |> assign(:test_result, nil)
    |> assign(:pending_api_key, nil)
  end

  defp apply_action(socket, :edit, %{"id" => id}) do
    connection = Products.get_provider_connection!(id)

    socket
    |> assign(:page_title, "Printify settings")
    |> assign(:connection, connection)
    |> assign(:form, to_form(ProviderConnection.changeset(connection, %{})))
    |> assign(:testing, false)
    |> assign(:test_result, nil)
    |> assign(:pending_api_key, nil)
  end

  @impl true
  def handle_event("validate", %{"provider_connection" => params}, socket) do
    form =
      socket.assigns.connection
      |> ProviderConnection.changeset(params)
      |> Map.put(:action, :validate)
      |> to_form()

    # Store api_key separately since changeset encrypts it immediately
    {:noreply, assign(socket, form: form, pending_api_key: params["api_key"])}
  end

  @impl true
  def handle_event("test_connection", _params, socket) do
    socket = assign(socket, testing: true, test_result: nil)

    # Use pending_api_key from validation, or fall back to existing encrypted key
    api_key =
      socket.assigns[:pending_api_key] ||
        ProviderConnection.get_api_key(socket.assigns.connection)

    if api_key && api_key != "" do
      temp_conn = %ProviderConnection{
        provider_type: "printify",
        api_key_encrypted: encrypt_api_key(api_key)
      }

      result = Providers.test_connection(temp_conn)
      {:noreply, assign(socket, testing: false, test_result: result)}
    else
      {:noreply, assign(socket, testing: false, test_result: {:error, :no_api_key})}
    end
  end

  @impl true
  def handle_event("save", %{"provider_connection" => params}, socket) do
    save_connection(socket, socket.assigns.live_action, params)
  end

  defp save_connection(socket, :new, params) do
    params =
      params
      |> Map.put("provider_type", "printify")
      |> maybe_add_shop_config(socket.assigns.test_result)
      |> maybe_add_name(socket.assigns.test_result)

    case Products.create_provider_connection(params) do
      {:ok, _connection} ->
        {:noreply,
         socket
         |> put_flash(:info, "Connected to Printify!")
         |> push_navigate(to: ~p"/admin/settings")}

      {:error, %Ecto.Changeset{} = changeset} ->
        {:noreply, assign(socket, form: to_form(changeset))}
    end
  end

  defp save_connection(socket, :edit, params) do
    case Products.update_provider_connection(socket.assigns.connection, params) do
      {:ok, _connection} ->
        {:noreply,
         socket
         |> put_flash(:info, "Settings saved")
         |> push_navigate(to: ~p"/admin/settings")}

      {:error, %Ecto.Changeset{} = changeset} ->
        {:noreply, assign(socket, form: to_form(changeset))}
    end
  end

  defp maybe_add_shop_config(params, {:ok, %{shop_id: shop_id}}) do
    config = Map.get(params, "config", %{}) |> Map.put("shop_id", to_string(shop_id))
    Map.put(params, "config", config)
  end

  defp maybe_add_shop_config(params, _), do: params

  defp maybe_add_name(params, {:ok, %{shop_name: shop_name}}) when is_binary(shop_name) do
    Map.put_new(params, "name", shop_name)
  end

  defp maybe_add_name(params, _) do
    Map.put_new(params, "name", "Printify")
  end

  defp encrypt_api_key(api_key) do
    case SimpleshopTheme.Vault.encrypt(api_key) do
      {:ok, encrypted} -> encrypted
      _ -> nil
    end
  end

  defp format_error(:no_api_key), do: "Please enter your connection key"
  defp format_error(:unauthorized), do: "That key doesn't seem to be valid"
  defp format_error(:timeout), do: "Couldn't reach Printify - try again"
  defp format_error({:http_error, _code}), do: "Something went wrong - try again"
  defp format_error(error) when is_binary(error), do: error
  defp format_error(_), do: "Connection failed - check your key and try again"
end
