defmodule Berrypod.Providers.PrintifyTest do
  use Berrypod.DataCase, async: true

  alias Berrypod.Providers.Printify

  import Berrypod.ProductsFixtures

  describe "provider_type/0" do
    test "returns printify" do
      assert Printify.provider_type() == "printify"
    end
  end

  describe "test_connection/1" do
    test "returns error when no API key" do
      conn = %Berrypod.Products.ProviderConnection{
        provider_type: "printify",
        api_key_encrypted: nil
      }

      assert {:error, :no_api_key} = Printify.test_connection(conn)
    end
  end

  describe "fetch_products/1" do
    test "returns error when no shop_id in config" do
      conn = %Berrypod.Products.ProviderConnection{
        provider_type: "printify",
        api_key_encrypted: nil,
        config: %{}
      }

      assert {:error, :no_shop_id} = Printify.fetch_products(conn)
    end

    test "returns error when no API key" do
      conn = %Berrypod.Products.ProviderConnection{
        provider_type: "printify",
        api_key_encrypted: nil,
        config: %{"shop_id" => "12345"}
      }

      assert {:error, :no_api_key} = Printify.fetch_products(conn)
    end
  end

  describe "product normalization" do
    test "normalizes Printify product response correctly" do
      # Use the fixture response
      raw = printify_product_response()

      # Call the private normalize function via the module
      # We test this indirectly through the public API, but we can also
      # verify the expected structure
      normalized = normalize_product(raw)

      assert normalized[:provider_product_id] == "12345"
      assert normalized[:title] == "Classic T-Shirt"
      assert normalized[:description] == "A comfortable cotton t-shirt"
      assert normalized[:category] == "Apparel"

      # Check images
      assert length(normalized[:images]) == 2
      [img1, img2] = normalized[:images]
      assert img1[:src] == "https://printify.com/img1.jpg"
      assert img1[:position] == 0
      assert img2[:position] == 1

      # Check variants
      assert length(normalized[:variants]) == 2
      [var1, _var2] = normalized[:variants]
      assert var1[:provider_variant_id] == "100"
      assert var1[:title] == "Solid White / S"
      assert var1[:price] == 2500
      assert var1[:is_enabled] == true
    end
  end

  # Helper to call private function for testing
  # In production, we'd test this through the public API
  defp normalize_product(raw) do
    # Replicate the normalization logic for testing
    %{
      provider_product_id: to_string(raw["id"]),
      title: raw["title"],
      description: raw["description"],
      category: extract_category(raw),
      images: normalize_images(raw["images"] || []),
      variants: normalize_variants(raw["variants"] || []),
      provider_data: %{
        blueprint_id: raw["blueprint_id"],
        print_provider_id: raw["print_provider_id"],
        tags: raw["tags"] || [],
        options: raw["options"] || [],
        raw: raw
      }
    }
  end

  defp normalize_images(images) do
    images
    |> Enum.with_index()
    |> Enum.map(fn {img, index} ->
      %{
        src: img["src"],
        position: img["position"] || index,
        alt: nil
      }
    end)
  end

  defp normalize_variants(variants) do
    Enum.map(variants, fn var ->
      %{
        provider_variant_id: to_string(var["id"]),
        title: var["title"],
        sku: var["sku"],
        price: var["price"],
        cost: var["cost"],
        options: normalize_variant_options(var),
        is_enabled: var["is_enabled"] == true,
        is_available: var["is_available"] == true
      }
    end)
  end

  defp normalize_variant_options(variant) do
    title = variant["title"] || ""
    parts = String.split(title, " / ")
    option_names = ["Size", "Color", "Style"]

    parts
    |> Enum.with_index()
    |> Enum.reduce(%{}, fn {value, index}, acc ->
      key = Enum.at(option_names, index) || "Option #{index + 1}"
      Map.put(acc, key, value)
    end)
  end

  defp extract_category(raw) do
    tags = raw["tags"] || []

    cond do
      "apparel" in tags or "clothing" in tags -> "Apparel"
      "homeware" in tags or "home" in tags -> "Homewares"
      "accessories" in tags -> "Accessories"
      "art" in tags or "print" in tags -> "Art Prints"
      true -> nil
    end
  end
end
