defmodule SimpleshopTheme.Printify.Client do
  @moduledoc """
  HTTP client for the Printify API.

  Handles authentication and provides low-level API access.
  Requires PRINTIFY_API_TOKEN environment variable to be set.
  """

  @base_url "https://api.printify.com/v1"

  @doc """
  Get the API token from environment.
  """
  def api_token do
    System.get_env("PRINTIFY_API_TOKEN") ||
      raise "PRINTIFY_API_TOKEN environment variable is not set"
  end

  @doc """
  Make a GET request to the Printify API.
  """
  def get(path, opts \\ []) do
    url = @base_url <> path

    case Req.get(url, headers: auth_headers(), receive_timeout: 30_000) do
      {:ok, %Req.Response{status: status, body: body}} when status in 200..299 ->
        {:ok, body}

      {:ok, %Req.Response{status: status, body: body}} ->
        {:error, {status, body}}

      {:error, reason} ->
        {:error, reason}
    end
  end

  @doc """
  Make a POST request to the Printify API.
  """
  def post(path, body, opts \\ []) do
    url = @base_url <> path

    case Req.post(url, json: body, headers: auth_headers(), receive_timeout: 60_000) do
      {:ok, %Req.Response{status: status, body: body}} when status in 200..299 ->
        {:ok, body}

      {:ok, %Req.Response{status: status, body: body}} ->
        {:error, {status, body}}

      {:error, reason} ->
        {:error, reason}
    end
  end

  @doc """
  Make a DELETE request to the Printify API.
  """
  def delete(path, opts \\ []) do
    url = @base_url <> path

    case Req.delete(url, headers: auth_headers(), receive_timeout: 30_000) do
      {:ok, %Req.Response{status: status, body: body}} when status in 200..299 ->
        {:ok, body}

      {:ok, %Req.Response{status: status}} when status == 204 ->
        {:ok, nil}

      {:ok, %Req.Response{status: status, body: body}} ->
        {:error, {status, body}}

      {:error, reason} ->
        {:error, reason}
    end
  end

  @doc """
  Get all shops for the authenticated account.
  """
  def get_shops do
    get("/shops.json")
  end

  @doc """
  Get the first shop ID for the account.
  """
  def get_shop_id do
    case get_shops() do
      {:ok, shops} when is_list(shops) and length(shops) > 0 ->
        {:ok, hd(shops)["id"]}

      {:ok, []} ->
        {:error, :no_shops}

      error ->
        error
    end
  end

  @doc """
  Get all blueprints (product types) from the catalog.
  """
  def get_blueprints do
    get("/catalog/blueprints.json")
  end

  @doc """
  Get print providers for a specific blueprint.
  """
  def get_print_providers(blueprint_id) do
    get("/catalog/blueprints/#{blueprint_id}/print_providers.json")
  end

  @doc """
  Get variants for a specific blueprint and print provider.
  """
  def get_variants(blueprint_id, print_provider_id) do
    get("/catalog/blueprints/#{blueprint_id}/print_providers/#{print_provider_id}/variants.json")
  end

  @doc """
  Get shipping information for a blueprint/provider combination.
  """
  def get_shipping(blueprint_id, print_provider_id) do
    get("/catalog/blueprints/#{blueprint_id}/print_providers/#{print_provider_id}/shipping.json")
  end

  @doc """
  Upload an image to Printify via URL.
  """
  def upload_image(file_name, url) do
    post("/uploads/images.json", %{
      file_name: file_name,
      url: url
    })
  end

  @doc """
  Create a product in a shop.
  """
  def create_product(shop_id, product_data) do
    post("/shops/#{shop_id}/products.json", product_data)
  end

  @doc """
  Get a product by ID.
  """
  def get_product(shop_id, product_id) do
    get("/shops/#{shop_id}/products/#{product_id}.json")
  end

  @doc """
  Delete a product from a shop.
  """
  def delete_product(shop_id, product_id) do
    delete("/shops/#{shop_id}/products/#{product_id}.json")
  end

  @doc """
  Download a file from a URL to a local path.
  """
  def download_file(url, output_path) do
    case Req.get(url, into: File.stream!(output_path), receive_timeout: 60_000) do
      {:ok, %Req.Response{status: status}} when status in 200..299 ->
        {:ok, output_path}

      {:ok, %Req.Response{status: status}} ->
        File.rm(output_path)
        {:error, {:http_error, status}}

      {:error, reason} ->
        File.rm(output_path)
        {:error, reason}
    end
  end

  defp auth_headers do
    [
      {"Authorization", "Bearer #{api_token()}"},
      {"Content-Type", "application/json"}
    ]
  end
end
