defmodule Towerops.DevicesFixtures do
  @moduledoc """
  This module defines test helpers for creating devices with all required fields.
  """

  alias Towerops.Devices

  @doc """
  Generate a device with all required fields.
  """
  def device_fixture(attrs \\ %{}) do
    # Handle organization_id specially to ensure proper site creation
    {organization_id, attrs} = Map.pop(attrs, :organization_id)
    {organization_id, attrs} = if organization_id, do: {organization_id, attrs}, else: Map.pop(attrs, "organization_id")

    # Ensure organization and site exist
    organization =
      attrs[:organization] || Map.get(attrs, "organization") ||
        if organization_id, do: get_organization(organization_id), else: create_organization()

    site =
      attrs[:site] || Map.get(attrs, "site") || create_site(organization)

    # Default device attributes
    default_attrs = %{
      name: "Test Device #{System.unique_integer([:positive])}",
      ip_address: "192.168.1.#{:rand.uniform(254)}",
      snmp_enabled: true,
      snmp_version: "2c",
      snmp_community: "public",
      snmp_port: 161,
      site_id: site.id,
      organization_id: organization.id
    }

    # Merge with provided attrs, converting string keys if needed
    merged_attrs =
      Map.merge(
        default_attrs,
        attrs |> Map.drop([:organization, :site, "organization", "site"]) |> Map.new(fn {k, v} -> {to_atom_key(k), v} end)
      )

    {:ok, device} = Devices.create_device(merged_attrs, bypass_limits: true)
    device
  end

  defp to_atom_key(key) when is_atom(key), do: key
  defp to_atom_key(key) when is_binary(key), do: String.to_existing_atom(key)

  defp get_organization(organization_id) do
    Towerops.Organizations.get_organization!(organization_id)
  end

  defp create_organization do
    user = Towerops.AccountsFixtures.user_fixture()
    {:ok, organization} = Towerops.Organizations.create_organization(%{name: "Test Org"}, user.id)
    organization
  end

  defp create_site(organization) do
    {:ok, site} =
      Towerops.Sites.create_site(%{
        name: "Test Site #{System.unique_integer([:positive])}",
        organization_id: organization.id
      })

    site
  end
end
