defmodule Towerops.Devices.MikrotikBackups.DifferTest do
  use ExUnit.Case, async: true

  alias Towerops.Devices.MikrotikBackups.Differ

  describe "mask_sensitive_data/1" do
    test "masks passwords in user set commands" do
      config = "/user set admin password=SuperSecret123"
      masked = Differ.mask_sensitive_data(config)

      refute String.contains?(masked, "SuperSecret123")
      assert String.contains?(masked, "***MASKED:")
      # Hash should be consistent
      assert masked == Differ.mask_sensitive_data(config)
    end

    test "masks passwords in user add commands" do
      config = "/user add name=admin password=MyPassword123 group=full"
      masked = Differ.mask_sensitive_data(config)

      refute String.contains?(masked, "MyPassword123")
      assert String.contains?(masked, "password=***MASKED:")
    end

    test "masks SNMP community strings" do
      config = "/snmp community set mycommunity name=mycommunity"
      masked = Differ.mask_sensitive_data(config)

      refute String.contains?(masked, "mycommunity")
      assert String.contains?(masked, "***MASKED:")
    end

    test "masks IPsec secrets" do
      config = "/ip ipsec peer set peer1 secret=MyVpnSecret123"
      masked = Differ.mask_sensitive_data(config)

      refute String.contains?(masked, "MyVpnSecret123")
      assert String.contains?(masked, "secret=***MASKED:")
    end

    test "masks wireless WPA pre-shared keys" do
      config = "/interface wireless security-profiles set profile1 wpa-pre-shared-key=WifiPassword123"
      masked = Differ.mask_sensitive_data(config)

      refute String.contains?(masked, "WifiPassword123")
      assert String.contains?(masked, "wpa-pre-shared-key=***MASKED:")
    end

    test "masks wireless WPA2 pre-shared keys" do
      config = "/interface wireless security-profiles set profile1 wpa2-pre-shared-key=WifiPassword456"
      masked = Differ.mask_sensitive_data(config)

      refute String.contains?(masked, "WifiPassword456")
      assert String.contains?(masked, "wpa2-pre-shared-key=***MASKED:")
    end

    test "preserves non-sensitive configuration" do
      config = """
      /interface bridge
      add name=bridge1
      /ip address
      add address=192.168.1.1/24 interface=bridge1
      """

      masked = Differ.mask_sensitive_data(config)
      assert masked == config
    end

    test "different passwords produce different hashes" do
      config1 = "/user set admin password=Password1"
      config2 = "/user set admin password=Password2"

      masked1 = Differ.mask_sensitive_data(config1)
      masked2 = Differ.mask_sensitive_data(config2)

      refute masked1 == masked2
    end

    test "handles multiline configuration with multiple secrets" do
      config = """
      /user set admin password=AdminPass123
      /snmp community set public name=public
      /ip ipsec peer set peer1 secret=VpnSecret456
      /interface wireless security-profiles set profile1 wpa-pre-shared-key=WifiPass789
      """

      masked = Differ.mask_sensitive_data(config)

      refute String.contains?(masked, "AdminPass123")
      refute String.contains?(masked, "VpnSecret456")
      refute String.contains?(masked, "WifiPass789")
      assert String.match?(masked, ~r/password=\*\*\*MASKED:[a-f0-9]{8}\*\*\*/)
      assert String.match?(masked, ~r/secret=\*\*\*MASKED:[a-f0-9]{8}\*\*\*/)
      assert String.match?(masked, ~r/wpa-pre-shared-key=\*\*\*MASKED:[a-f0-9]{8}\*\*\*/)
    end
  end

  describe "generate_unified_diff/2" do
    test "generates unified diff for different configs" do
      config_a = """
      /interface bridge
      add name=bridge1
      /ip address
      add address=192.168.1.1/24 interface=bridge1
      """

      config_b = """
      /interface bridge
      add name=bridge1
      /ip address
      add address=192.168.2.1/24 interface=bridge1
      """

      {:ok, diff} = Differ.generate_unified_diff(config_a, config_b)

      assert String.contains?(diff, "-add address=192.168.1.1/24")
      assert String.contains?(diff, "+add address=192.168.2.1/24")
    end

    test "returns empty string for identical configs" do
      config = """
      /interface bridge
      add name=bridge1
      """

      {:ok, diff} = Differ.generate_unified_diff(config, config)

      assert diff == ""
    end

    test "shows additions" do
      config_a = """
      /interface bridge
      add name=bridge1
      """

      config_b = """
      /interface bridge
      add name=bridge1
      add name=bridge2
      """

      {:ok, diff} = Differ.generate_unified_diff(config_a, config_b)

      assert String.contains?(diff, "+add name=bridge2")
    end

    test "shows deletions" do
      config_a = """
      /interface bridge
      add name=bridge1
      add name=bridge2
      """

      config_b = """
      /interface bridge
      add name=bridge1
      """

      {:ok, diff} = Differ.generate_unified_diff(config_a, config_b)

      assert String.contains?(diff, "-add name=bridge2")
    end

    test "handles empty configs" do
      {:ok, diff} = Differ.generate_unified_diff("", "")
      assert diff == ""
    end

    test "handles one empty config" do
      config = "/interface bridge\nadd name=bridge1\n"

      {:ok, diff} = Differ.generate_unified_diff("", config)
      assert String.contains?(diff, "+/interface bridge")
      assert String.contains?(diff, "+add name=bridge1")
    end
  end

  describe "calculate_diff_stats/1" do
    test "calculates stats from unified diff" do
      diff = """
      --- a
      +++ b
      @@ -1,3 +1,3 @@
       /interface bridge
      -add name=bridge1
      +add name=bridge2
       /ip address
      """

      stats = Differ.calculate_diff_stats(diff)

      assert stats.additions == 1
      assert stats.deletions == 1
      assert stats.changes == 1
    end

    test "returns zero stats for empty diff" do
      stats = Differ.calculate_diff_stats("")

      assert stats.additions == 0
      assert stats.deletions == 0
      assert stats.changes == 0
    end

    test "counts multiple additions and deletions" do
      diff = """
      --- a
      +++ b
      @@ -1,5 +1,6 @@
       /interface bridge
      -add name=bridge1
      -add name=bridge2
      +add name=bridge3
      +add name=bridge4
      +add name=bridge5
       /ip address
      """

      stats = Differ.calculate_diff_stats(diff)

      assert stats.additions == 3
      assert stats.deletions == 2
      assert stats.changes == 2
    end
  end
end
