defmodule Towerops.Contexts.ConfigChangeTrackerTest do
  use Towerops.DataCase, async: true

  alias Towerops.Contexts.ConfigChangeTracker

  describe "capture_config_state/1" do
    test "captures all config fields from organization struct" do
      org = %{
        snmp_community: "public",
        mikrotik_username: "admin",
        mikrotik_password: "password",
        mikrotik_port: 8729,
        mikrotik_use_ssl: true,
        mikrotik_enabled: true
      }

      result = ConfigChangeTracker.capture_config_state(org)

      assert result == %{
               snmp_community: "public",
               mikrotik_username: "admin",
               mikrotik_password: "password",
               mikrotik_port: 8729,
               mikrotik_use_ssl: true,
               mikrotik_enabled: true
             }
    end

    test "captures partial config fields with nils" do
      site = %{
        snmp_community: "private",
        mikrotik_username: nil,
        mikrotik_password: nil,
        mikrotik_port: nil,
        mikrotik_use_ssl: nil,
        mikrotik_enabled: nil
      }

      result = ConfigChangeTracker.capture_config_state(site)

      assert result.snmp_community == "private"
      assert result.mikrotik_username == nil
      assert result.mikrotik_password == nil
    end

    test "handles struct with missing fields gracefully" do
      minimal = %{snmp_community: "test"}

      result = ConfigChangeTracker.capture_config_state(minimal)

      assert result.snmp_community == "test"
      assert result.mikrotik_username == nil
      assert result.mikrotik_password == nil
      assert result.mikrotik_port == nil
      assert result.mikrotik_use_ssl == nil
      assert result.mikrotik_enabled == nil
    end
  end

  describe "snmp_changed?/2" do
    test "returns true when SNMP community changed" do
      old_state = %{snmp_community: "public"}
      updated = %{snmp_community: "private"}

      assert ConfigChangeTracker.snmp_changed?(updated, old_state) == true
    end

    test "returns false when SNMP community unchanged" do
      old_state = %{snmp_community: "public"}
      updated = %{snmp_community: "public"}

      assert ConfigChangeTracker.snmp_changed?(updated, old_state) == false
    end

    test "returns true when SNMP community changes from nil to value" do
      old_state = %{snmp_community: nil}
      updated = %{snmp_community: "public"}

      assert ConfigChangeTracker.snmp_changed?(updated, old_state) == true
    end

    test "returns true when SNMP community changes from value to nil" do
      old_state = %{snmp_community: "public"}
      updated = %{snmp_community: nil}

      assert ConfigChangeTracker.snmp_changed?(updated, old_state) == true
    end
  end

  describe "mikrotik_changed?/2" do
    test "returns true when MikroTik username changed" do
      old_state = %{
        snmp_community: "public",
        mikrotik_username: "admin",
        mikrotik_password: "pass",
        mikrotik_port: 8729,
        mikrotik_use_ssl: true,
        mikrotik_enabled: true
      }

      updated = %{
        snmp_community: "public",
        mikrotik_username: "root",
        mikrotik_password: "pass",
        mikrotik_port: 8729,
        mikrotik_use_ssl: true,
        mikrotik_enabled: true
      }

      assert ConfigChangeTracker.mikrotik_changed?(updated, old_state) == true
    end

    test "returns true when MikroTik password changed" do
      old_state = %{
        mikrotik_username: "admin",
        mikrotik_password: "oldpass",
        mikrotik_port: 8729,
        mikrotik_use_ssl: true,
        mikrotik_enabled: true
      }

      updated = %{
        mikrotik_username: "admin",
        mikrotik_password: "newpass",
        mikrotik_port: 8729,
        mikrotik_use_ssl: true,
        mikrotik_enabled: true
      }

      assert ConfigChangeTracker.mikrotik_changed?(updated, old_state) == true
    end

    test "returns true when MikroTik port changed" do
      old_state = %{
        mikrotik_username: "admin",
        mikrotik_password: "pass",
        mikrotik_port: 8729,
        mikrotik_use_ssl: true,
        mikrotik_enabled: true
      }

      updated = %{
        mikrotik_username: "admin",
        mikrotik_password: "pass",
        mikrotik_port: 8728,
        mikrotik_use_ssl: true,
        mikrotik_enabled: true
      }

      assert ConfigChangeTracker.mikrotik_changed?(updated, old_state) == true
    end

    test "returns true when MikroTik SSL setting changed" do
      old_state = %{
        mikrotik_username: "admin",
        mikrotik_password: "pass",
        mikrotik_port: 8729,
        mikrotik_use_ssl: true,
        mikrotik_enabled: true
      }

      updated = %{
        mikrotik_username: "admin",
        mikrotik_password: "pass",
        mikrotik_port: 8729,
        mikrotik_use_ssl: false,
        mikrotik_enabled: true
      }

      assert ConfigChangeTracker.mikrotik_changed?(updated, old_state) == true
    end

    test "returns true when MikroTik enabled setting changed" do
      old_state = %{
        mikrotik_username: "admin",
        mikrotik_password: "pass",
        mikrotik_port: 8729,
        mikrotik_use_ssl: true,
        mikrotik_enabled: false
      }

      updated = %{
        mikrotik_username: "admin",
        mikrotik_password: "pass",
        mikrotik_port: 8729,
        mikrotik_use_ssl: true,
        mikrotik_enabled: true
      }

      assert ConfigChangeTracker.mikrotik_changed?(updated, old_state) == true
    end

    test "returns false when no MikroTik fields changed" do
      old_state = %{
        snmp_community: "public",
        mikrotik_username: "admin",
        mikrotik_password: "pass",
        mikrotik_port: 8729,
        mikrotik_use_ssl: true,
        mikrotik_enabled: true
      }

      updated = %{
        snmp_community: "public",
        mikrotik_username: "admin",
        mikrotik_password: "pass",
        mikrotik_port: 8729,
        mikrotik_use_ssl: true,
        mikrotik_enabled: true
      }

      assert ConfigChangeTracker.mikrotik_changed?(updated, old_state) == false
    end

    test "returns false when only SNMP community changed (not MikroTik field)" do
      old_state = %{
        snmp_community: "public",
        mikrotik_username: "admin",
        mikrotik_password: "pass",
        mikrotik_port: 8729,
        mikrotik_use_ssl: true,
        mikrotik_enabled: true
      }

      updated = %{
        snmp_community: "private",
        mikrotik_username: "admin",
        mikrotik_password: "pass",
        mikrotik_port: 8729,
        mikrotik_use_ssl: true,
        mikrotik_enabled: true
      }

      assert ConfigChangeTracker.mikrotik_changed?(updated, old_state) == false
    end

    test "returns true when MikroTik field changes from nil to value" do
      old_state = %{
        mikrotik_username: nil,
        mikrotik_password: nil,
        mikrotik_port: nil,
        mikrotik_use_ssl: nil,
        mikrotik_enabled: nil
      }

      updated = %{
        mikrotik_username: "admin",
        mikrotik_password: nil,
        mikrotik_port: nil,
        mikrotik_use_ssl: nil,
        mikrotik_enabled: nil
      }

      assert ConfigChangeTracker.mikrotik_changed?(updated, old_state) == true
    end
  end

  describe "extract_mikrotik_attrs/1" do
    test "extracts all MikroTik fields from struct" do
      struct = %{
        mikrotik_username: "admin",
        mikrotik_password: "password",
        mikrotik_port: 8729,
        mikrotik_use_ssl: true,
        mikrotik_enabled: true,
        snmp_community: "public"
      }

      result = ConfigChangeTracker.extract_mikrotik_attrs(struct)

      assert result == %{
               mikrotik_username: "admin",
               mikrotik_password: "password",
               mikrotik_port: 8729,
               mikrotik_use_ssl: true,
               mikrotik_enabled: true
             }
    end

    test "extracts MikroTik fields with nils" do
      struct = %{
        mikrotik_username: "admin",
        mikrotik_password: nil,
        mikrotik_port: nil,
        mikrotik_use_ssl: nil,
        mikrotik_enabled: false
      }

      result = ConfigChangeTracker.extract_mikrotik_attrs(struct)

      assert result.mikrotik_username == "admin"
      assert result.mikrotik_password == nil
      assert result.mikrotik_port == nil
      assert result.mikrotik_use_ssl == nil
      assert result.mikrotik_enabled == false
    end

    test "does not include SNMP community field" do
      struct = %{
        snmp_community: "public",
        mikrotik_username: "admin",
        mikrotik_password: "pass",
        mikrotik_port: 8729,
        mikrotik_use_ssl: true,
        mikrotik_enabled: true
      }

      result = ConfigChangeTracker.extract_mikrotik_attrs(struct)

      refute Map.has_key?(result, :snmp_community)
    end
  end
end
