defmodule SimpleshopTheme.Mockups.Generator do
  @moduledoc """
  Generates product mockups using the Printify API.

  This module handles the end-to-end process of:
  1. Looking up product blueprints and variants
  2. Downloading artwork from Unsplash
  3. Uploading artwork to Printify
  4. Creating products with the artwork
  5. Downloading generated mockup images
  6. Optionally cleaning up created products
  """

  alias SimpleshopTheme.Clients.Printify, as: Client

  @output_dir "priv/static/mockups"

  @doc """
  Product definitions with their artwork URLs and Printify product types.
  """
  def product_definitions do
    [
      %{
        name: "Mountain Sunrise Art Print",
        slug: "mountain-sunrise-print",
        category: "Art Prints",
        artwork_url: unsplash_download_url("UweNcthlmDc"),
        product_type: :poster,
        price: 2400
      },
      %{
        name: "Ocean Waves Art Print",
        slug: "ocean-waves-print",
        category: "Art Prints",
        artwork_url: unsplash_download_url("XRhUTUVuXAE"),
        product_type: :poster,
        price: 2400
      },
      %{
        name: "Wildflower Meadow Art Print",
        slug: "wildflower-meadow-print",
        category: "Art Prints",
        artwork_url: unsplash_download_url("QvjL4y7SF9k"),
        product_type: :poster,
        price: 2400
      },
      %{
        name: "Geometric Abstract Art Print",
        slug: "geometric-abstract-print",
        category: "Art Prints",
        artwork_url: unsplash_download_url("-6GvTDpkkPU"),
        product_type: :poster,
        price: 2800
      },
      %{
        name: "Botanical Illustration Print",
        slug: "botanical-illustration-print",
        category: "Art Prints",
        artwork_url: unsplash_download_url("FNtNIDQWUZY"),
        product_type: :poster,
        price: 2400
      },
      %{
        name: "Forest Silhouette T-Shirt",
        slug: "forest-silhouette-tshirt",
        category: "Apparel",
        artwork_url: unsplash_download_url("EhvMzMRO4_o"),
        product_type: :tshirt,
        price: 2999
      },
      %{
        name: "Forest Light Hoodie",
        slug: "forest-light-hoodie",
        category: "Apparel",
        artwork_url: unsplash_download_url("FwVkxITt8Bg"),
        product_type: :hoodie,
        price: 4499
      },
      %{
        name: "Wildflower Meadow Tote Bag",
        slug: "wildflower-meadow-tote",
        category: "Apparel",
        artwork_url: unsplash_download_url("QvjL4y7SF9k"),
        product_type: :tote,
        price: 1999
      },
      %{
        name: "Sunset Gradient Tote Bag",
        slug: "sunset-gradient-tote",
        category: "Apparel",
        artwork_url: unsplash_download_url("XRhUTUVuXAE"),
        product_type: :tote,
        price: 1999
      },
      %{
        name: "Fern Leaf Mug",
        slug: "fern-leaf-mug",
        category: "Homewares",
        artwork_url: unsplash_download_url("bYiJojtkHnc"),
        product_type: :mug,
        price: 1499
      },
      %{
        name: "Ocean Waves Cushion",
        slug: "ocean-waves-cushion",
        category: "Homewares",
        artwork_url: unsplash_download_url("XRhUTUVuXAE"),
        product_type: :cushion,
        price: 2999
      },
      %{
        name: "Night Sky Blanket",
        slug: "night-sky-blanket",
        category: "Homewares",
        artwork_url: unsplash_download_url("oQR1B87HsNs"),
        product_type: :blanket,
        price: 5999
      },
      %{
        name: "Autumn Leaves Notebook",
        slug: "autumn-leaves-notebook",
        category: "Stationery",
        artwork_url: unsplash_download_url("Aa3ALtIxEGY"),
        product_type: :notebook,
        price: 1999
      },
      %{
        name: "Monstera Leaf Notebook",
        slug: "monstera-leaf-notebook",
        category: "Stationery",
        artwork_url: unsplash_download_url("hETU8_b2IM0"),
        product_type: :notebook,
        price: 1999
      },
      %{
        name: "Monstera Leaf Phone Case",
        slug: "monstera-leaf-phone-case",
        category: "Accessories",
        artwork_url: unsplash_download_url("hETU8_b2IM0"),
        product_type: :phone_case,
        price: 2499
      },
      %{
        name: "Blue Waves Laptop Sleeve",
        slug: "blue-waves-laptop-sleeve",
        category: "Accessories",
        artwork_url: unsplash_download_url("dYksH3vHorc"),
        product_type: :laptop_sleeve,
        price: 3499
      }
    ]
  end

  @doc """
  Blueprint configurations for each product type.
  These IDs need to be looked up from the Printify catalog.
  """
  def blueprint_config do
    %{
      # Search terms matched to Printify's actual blueprint titles (partial match)
      poster: %{blueprint_id: nil, print_provider_id: nil, search_term: "Matte Posters"},
      tshirt: %{blueprint_id: nil, print_provider_id: nil, search_term: "Softstyle T-Shirt"},
      hoodie: %{blueprint_id: nil, print_provider_id: nil, search_term: "Pullover Hoodie"},
      tote: %{blueprint_id: nil, print_provider_id: nil, search_term: "Cotton Tote Bag"},
      mug: %{blueprint_id: nil, print_provider_id: nil, search_term: "Mug 11oz"},
      cushion: %{
        blueprint_id: nil,
        print_provider_id: nil,
        search_term: "Spun Polyester Square Pillow"
      },
      blanket: %{blueprint_id: nil, print_provider_id: nil, search_term: "Sherpa Fleece Blanket"},
      notebook: %{
        blueprint_id: nil,
        print_provider_id: nil,
        search_term: "Hardcover Journal Matte"
      },
      phone_case: %{blueprint_id: nil, print_provider_id: nil, search_term: "Tough Phone Cases"},
      laptop_sleeve: %{blueprint_id: nil, print_provider_id: nil, search_term: "Laptop Sleeve"}
    }
  end

  @doc """
  Generate Unsplash download URL from photo ID.
  Uses the Unsplash download API which provides high-quality images.
  """
  def unsplash_download_url(photo_id) do
    "https://unsplash.com/photos/#{photo_id}/download?force=true"
  end

  @doc """
  Search for a blueprint by name/term.
  """
  def find_blueprint(search_term) do
    case Client.get_blueprints() do
      {:ok, blueprints} ->
        found =
          Enum.find(blueprints, fn bp ->
            String.contains?(String.downcase(bp["title"] || ""), String.downcase(search_term))
          end)

        case found do
          nil -> {:error, {:blueprint_not_found, search_term}}
          bp -> {:ok, bp}
        end

      error ->
        error
    end
  end

  @doc """
  Find a suitable print provider for a blueprint.
  Prefers providers with good ratings and reasonable pricing.
  """
  def find_print_provider(blueprint_id) do
    case Client.get_print_providers(blueprint_id) do
      {:ok, providers} when is_list(providers) and providers != [] ->
        # Just pick the first provider for simplicity
        {:ok, hd(providers)}

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

      error ->
        error
    end
  end

  @doc """
  Get variant and placeholder information for a blueprint/provider combination.
  """
  def get_variant_info(blueprint_id, print_provider_id) do
    case Client.get_variants(blueprint_id, print_provider_id) do
      {:ok, %{"variants" => variants}} when is_list(variants) ->
        {:ok, variants}

      {:ok, variants} when is_list(variants) ->
        {:ok, variants}

      {:ok, response} when is_map(response) ->
        # Handle case where variants might be nested differently
        {:ok, response["variants"] || []}

      error ->
        error
    end
  end

  @doc """
  Upload artwork to Printify from a URL.
  """
  def upload_artwork(name, url) do
    file_name = "#{name}.jpg"
    Client.upload_image(file_name, url)
  end

  @doc """
  Calculate scale factor for "cover" behavior.
  Image will fill entire placeholder, cropping edges if necessary.
  Printify scale is relative to placeholder width (1.0 = artwork width matches placeholder width).
  """
  def calculate_cover_scale(artwork_width, artwork_height, placeholder_width, placeholder_height)
      when is_number(artwork_width) and is_number(artwork_height) and
             is_number(placeholder_width) and is_number(placeholder_height) and
             artwork_width > 0 and artwork_height > 0 and
             placeholder_width > 0 and placeholder_height > 0 do
    # For cover: use the larger scale to ensure full coverage
    width_scale = 1.0
    height_scale = placeholder_height * artwork_width / (artwork_height * placeholder_width)
    max(width_scale, height_scale)
  end

  def calculate_cover_scale(_, _, _, _), do: 1.0

  @doc """
  Create a product with the uploaded artwork.
  """
  def create_product(
        shop_id,
        product_def,
        image_id,
        image_width,
        image_height,
        blueprint_id,
        print_provider_id,
        variants
      ) do
    # Get the first variant for simplicity (typically a standard size/color)
    variant = hd(variants)
    variant_id = variant["id"]

    # Get placeholder info
    placeholders = variant["placeholders"] || []

    front_placeholder =
      Enum.find(placeholders, fn p -> p["position"] == "front" end) || hd(placeholders)

    # Extract placeholder dimensions and calculate cover scale
    placeholder_width = front_placeholder["width"]
    placeholder_height = front_placeholder["height"]

    scale =
      calculate_cover_scale(image_width, image_height, placeholder_width, placeholder_height)

    IO.puts(
      "  Scale calculation: artwork #{image_width}x#{image_height}, placeholder #{placeholder_width}x#{placeholder_height} -> scale #{Float.round(scale, 3)}"
    )

    product_data = %{
      title: product_def.name,
      description: "#{product_def.name} - Nature-inspired design from Wildprint Studio",
      blueprint_id: blueprint_id,
      print_provider_id: print_provider_id,
      variants: [
        %{
          id: variant_id,
          price: product_def.price,
          is_enabled: true
        }
      ],
      print_areas: [
        %{
          variant_ids: [variant_id],
          placeholders: [
            %{
              position: front_placeholder["position"] || "front",
              images: [
                %{
                  id: image_id,
                  x: 0.5,
                  y: 0.5,
                  scale: scale,
                  angle: 0
                }
              ]
            }
          ]
        }
      ]
    }

    Client.create_product(shop_id, product_data)
  end

  @doc """
  Extract mockup image URLs from a created product.
  """
  def extract_mockup_urls(product) do
    images = product["images"] || []
    Enum.map(images, fn img -> img["src"] end)
  end

  @doc """
  Download mockup images, save as WebP source, and generate variants.
  Sources are saved for regeneration on startup via VariantCache.
  """
  def download_mockups(product_slug, mockup_urls) do
    alias SimpleshopTheme.Images.Optimizer

    File.mkdir_p!(@output_dir)

    mockup_urls
    |> Enum.with_index(1)
    |> Enum.map(fn {url, index} ->
      basename = "#{product_slug}-#{index}"
      source_path = Path.join(@output_dir, "#{basename}.webp")
      IO.puts("  Processing mockup #{index}...")

      temp_path = Path.join(System.tmp_dir!(), "#{basename}-temp.jpg")

      with {:ok, _} <- Client.download_file(url, temp_path),
           {:ok, image_data} <- File.read(temp_path),
           {:ok, webp_data, source_width, _} <- Optimizer.to_optimized_webp(image_data),
           :ok <- File.write(source_path, webp_data),
           {:ok, _} <- Optimizer.process_file(webp_data, basename, @output_dir) do
        File.rm(temp_path)
        IO.puts("    Saved source + variants for #{basename} (#{source_width}px)")
        {:ok, basename, source_width}
      else
        {:error, reason} ->
          File.rm(temp_path)
          {:error, {url, reason}}
      end
    end)
  end

  @doc """
  Generate mockups for all products.
  """
  def generate_all(opts \\ []) do
    cleanup = Keyword.get(opts, :cleanup, false)

    IO.puts("Starting mockup generation...")
    IO.puts("")

    # Get shop ID
    IO.puts("Fetching shop ID...")
    {:ok, shop_id} = Client.get_shop_id()
    IO.puts("Using shop ID: #{shop_id}")
    IO.puts("")

    results =
      product_definitions()
      |> Enum.map(fn product_def ->
        IO.puts("Processing: #{product_def.name}")
        result = generate_single(shop_id, product_def)

        case result do
          {:ok, product_id, mockup_paths} ->
            IO.puts("  ✓ Generated #{length(mockup_paths)} mockups")
            {:ok, product_def.slug, product_id, mockup_paths}

          {:error, reason} ->
            IO.puts("  ✗ Error: #{inspect(reason)}")
            {:error, product_def.slug, reason}
        end
      end)

    # Cleanup if requested
    if cleanup do
      IO.puts("")
      IO.puts("Cleaning up created products...")

      results
      |> Enum.filter(fn
        {:ok, _, _, _} -> true
        _ -> false
      end)
      |> Enum.each(fn {:ok, slug, product_id, _} ->
        IO.puts("  Deleting #{slug}...")
        Client.delete_product(shop_id, product_id)
      end)

      IO.puts("Cleanup complete.")
    end

    IO.puts("")
    IO.puts("Mockup generation complete!")
    IO.puts("Output directory: #{@output_dir}")

    results
  end

  @doc """
  Generate mockups for a single product.
  """
  def generate_single(shop_id, product_def) do
    config = blueprint_config()[product_def.product_type]

    with {:ok, blueprint} <- find_blueprint(config.search_term),
         blueprint_id = blueprint["id"],
         _ = IO.puts("  Found blueprint: #{blueprint["title"]} (#{blueprint_id})"),
         {:ok, provider} <- find_print_provider(blueprint_id),
         provider_id = provider["id"],
         _ = IO.puts("  Using provider: #{provider["title"]} (#{provider_id})"),
         {:ok, variants} <- get_variant_info(blueprint_id, provider_id),
         _ = IO.puts("  Found #{length(variants)} variants"),
         _ = IO.puts("  Uploading artwork..."),
         {:ok, upload} <- upload_artwork(product_def.slug, product_def.artwork_url),
         image_id = upload["id"],
         image_width = upload["width"],
         image_height = upload["height"],
         _ = IO.puts("  Artwork uploaded (ID: #{image_id}, #{image_width}x#{image_height})"),
         _ = IO.puts("  Creating product..."),
         {:ok, product} <-
           create_product(
             shop_id,
             product_def,
             image_id,
             image_width,
             image_height,
             blueprint_id,
             provider_id,
             variants
           ),
         product_id = product["id"],
         mockup_urls = extract_mockup_urls(product),
         _ = IO.puts("  Product created (ID: #{product_id})"),
         _ = IO.puts("  Downloading #{length(mockup_urls)} mockups..."),
         download_results <- download_mockups(product_def.slug, mockup_urls) do
      successful_downloads =
        download_results
        |> Enum.filter(&match?({:ok, _}, &1))
        |> Enum.map(fn {:ok, path} -> path end)

      {:ok, product_id, successful_downloads}
    end
  end

  @doc """
  List all available blueprints (for discovery).
  """
  def list_blueprints do
    case Client.get_blueprints() do
      {:ok, blueprints} ->
        blueprints
        |> Enum.map(fn bp -> {bp["id"], bp["title"]} end)
        |> Enum.sort_by(fn {_, title} -> title end)

      error ->
        error
    end
  end

  @doc """
  Search blueprints by keyword.
  """
  def search_blueprints(keyword) do
    case Client.get_blueprints() do
      {:ok, blueprints} ->
        blueprints
        |> Enum.filter(fn bp ->
          String.contains?(String.downcase(bp["title"] || ""), String.downcase(keyword))
        end)
        |> Enum.map(fn bp -> {bp["id"], bp["title"]} end)

      error ->
        error
    end
  end
end
