defmodule SnmpKit.SnmpLib.MIB.LoggerTest do
  use ExUnit.Case, async: false

  import ExUnit.CaptureLog

  alias SnmpKit.SnmpLib.MIB.Error
  alias SnmpKit.SnmpLib.MIB.Logger, as: MibLogger

  describe "log_compilation_start/2" do
    test "logs compilation start with options" do
      opts = [
        output_dir: "/tmp/mibs",
        format: :binary,
        optimize: true,
        vendor_quirks: [:cisco]
      ]

      capture_log(fn ->
        assert :ok = MibLogger.log_compilation_start("/path/to/test.mib", opts)
      end)
    end

    test "handles empty options" do
      capture_log(fn ->
        assert :ok = MibLogger.log_compilation_start("/path/to/test.mib", [])
      end)
    end
  end

  describe "log_compilation_success/2" do
    test "logs successful compilation" do
      capture_log(fn ->
        assert :ok = MibLogger.log_compilation_success("TEST-MIB", "/tmp/mibs/TEST-MIB.bin")
      end)
    end
  end

  describe "log_compilation_error/2" do
    test "logs compilation errors with error list" do
      errors = [
        %Error{type: :syntax_error, message: "Unexpected token"},
        %Error{type: :semantic_error, message: "Undefined symbol"}
      ]

      log =
        capture_log(fn ->
          assert :ok = MibLogger.log_compilation_error("TEST-MIB", errors)
        end)

      assert log =~ "MIB compilation failed"
    end

    test "logs empty error list" do
      capture_log(fn ->
        assert :ok = MibLogger.log_compilation_error("TEST-MIB", [])
      end)
    end
  end

  describe "log_compilation_warning/3" do
    test "logs compilation with warnings" do
      warnings = [
        %Error{type: :deprecated_syntax, message: "Old syntax used"},
        %Error{type: :naming_convention, message: "Non-standard naming"}
      ]

      capture_log(fn ->
        assert :ok =
                 MibLogger.log_compilation_warning("TEST-MIB", "/tmp/mibs/TEST-MIB.bin", warnings)
      end)
    end

    test "logs with empty warnings" do
      capture_log(fn ->
        assert :ok = MibLogger.log_compilation_warning("TEST-MIB", "/tmp/output", [])
      end)
    end
  end

  describe "log_batch_compilation_start/1" do
    test "logs batch compilation start" do
      capture_log(fn ->
        assert :ok = MibLogger.log_batch_compilation_start(10)
      end)
    end

    test "handles zero file count" do
      capture_log(fn ->
        assert :ok = MibLogger.log_batch_compilation_start(0)
      end)
    end
  end

  describe "log_batch_compilation_success/1" do
    test "logs batch compilation success" do
      capture_log(fn ->
        assert :ok = MibLogger.log_batch_compilation_success(8)
      end)
    end
  end

  describe "log_batch_compilation_error/2" do
    test "logs batch compilation with errors" do
      log =
        capture_log(fn ->
          assert :ok = MibLogger.log_batch_compilation_error(5, 3)
        end)

      assert log =~ "Batch MIB compilation completed with errors"
    end

    test "handles all errors" do
      capture_log(fn ->
        assert :ok = MibLogger.log_batch_compilation_error(0, 10)
      end)
    end
  end

  describe "log_compilation_complete/2" do
    test "logs compilation complete with results" do
      result = %{
        objects_count: 150,
        output_path: "/tmp/mibs/TEST-MIB.bin",
        compilation_time: 1250
      }

      capture_log(fn ->
        assert :ok = MibLogger.log_compilation_complete("TEST-MIB", result)
      end)
    end

    test "handles empty result map" do
      capture_log(fn ->
        assert :ok = MibLogger.log_compilation_complete("TEST-MIB", %{})
      end)
    end
  end

  describe "log_compilation_failed/2" do
    test "logs compilation failure with error types" do
      errors = [
        %Error{type: :syntax_error, message: "Error 1"},
        %Error{type: :syntax_error, message: "Error 2"},
        %Error{type: :semantic_error, message: "Error 3"}
      ]

      log =
        capture_log(fn ->
          assert :ok = MibLogger.log_compilation_failed("/path/to/test.mib", errors)
        end)

      assert log =~ "MIB compilation failed"
    end

    test "handles errors with different formats" do
      errors = [
        %Error{type: :syntax_error, message: "Error"},
        %{type: :custom_error},
        :atom_error,
        "string error"
      ]

      capture_log(fn ->
        assert :ok = MibLogger.log_compilation_failed("/path/to/test.mib", errors)
      end)
    end
  end

  describe "log_parse_progress/2" do
    test "logs parsing progress" do
      log =
        capture_log([level: :debug], fn ->
          assert :ok = MibLogger.log_parse_progress("tokenization", 1500)
        end)

      assert log =~ "Parse progress" or log == ""
    end

    test "handles zero count" do
      capture_log([level: :debug], fn ->
        assert :ok = MibLogger.log_parse_progress("parsing", 0)
      end)
    end
  end

  describe "log_import_resolution/2" do
    test "logs import resolution" do
      imported_mibs = ["SNMPv2-SMI", "SNMPv2-TC", "SNMPv2-CONF"]

      log =
        capture_log([level: :debug], fn ->
          assert :ok = MibLogger.log_import_resolution("TEST-MIB", imported_mibs)
        end)

      assert log =~ "Resolving imports" or log == ""
    end

    test "handles empty imports" do
      capture_log([level: :debug], fn ->
        assert :ok = MibLogger.log_import_resolution("TEST-MIB", [])
      end)
    end
  end

  describe "log_imports_resolved/3" do
    test "logs successful import resolution" do
      log =
        capture_log([level: :debug], fn ->
          assert :ok = MibLogger.log_imports_resolved("TEST-MIB", 8, 10)
        end)

      assert log =~ "Imports resolved" or log == ""
    end

    test "handles all imports resolved" do
      capture_log([level: :debug], fn ->
        assert :ok = MibLogger.log_imports_resolved("TEST-MIB", 5, 5)
      end)
    end

    test "handles zero total imports" do
      capture_log([level: :debug], fn ->
        assert :ok = MibLogger.log_imports_resolved("TEST-MIB", 0, 0)
      end)
    end
  end

  describe "log_codegen/3" do
    test "logs code generation results" do
      capture_log(fn ->
        assert :ok = MibLogger.log_codegen("TEST-MIB", 100, 350)
      end)
    end

    test "handles zero objects" do
      capture_log(fn ->
        assert :ok = MibLogger.log_codegen("TEST-MIB", 0, 0)
      end)
    end
  end

  describe "log_tokenization/3" do
    test "logs tokenization statistics" do
      log =
        capture_log([level: :debug], fn ->
          assert :ok = MibLogger.log_tokenization("TEST-MIB", 5000, 250)
        end)

      assert log =~ "Tokenization complete" or log == ""
    end

    test "handles zero lines" do
      capture_log([level: :debug], fn ->
        assert :ok = MibLogger.log_tokenization("TEST-MIB", 0, 0)
      end)
    end
  end

  describe "log_dependency_order/1" do
    test "logs dependency resolution order" do
      mib_order = ["SNMPv2-SMI", "SNMPv2-TC", "IF-MIB", "TEST-MIB"]

      log =
        capture_log([level: :debug], fn ->
          assert :ok = MibLogger.log_dependency_order(mib_order)
        end)

      assert log =~ "Dependency resolution complete" or log == ""
    end

    test "handles empty order" do
      capture_log([level: :debug], fn ->
        assert :ok = MibLogger.log_dependency_order([])
      end)
    end
  end

  describe "log_performance/2" do
    test "logs performance metrics" do
      metrics = [
        duration_ms: 1234,
        memory_mb: 45.6,
        cpu_usage: 23.5
      ]

      log =
        capture_log([level: :debug], fn ->
          assert :ok = MibLogger.log_performance("compilation", metrics)
        end)

      assert log =~ "Performance metrics" or log == ""
    end

    test "handles empty metrics" do
      capture_log([level: :debug], fn ->
        assert :ok = MibLogger.log_performance("test_phase", [])
      end)
    end
  end

  describe "log_warning/2" do
    test "logs warning with context" do
      context = %{file: "test.mib", line: 42, column: 10}

      capture_log(fn ->
        assert :ok = MibLogger.log_warning("Deprecated syntax detected", context)
      end)
    end

    test "logs warning without context" do
      capture_log(fn ->
        assert :ok = MibLogger.log_warning("Simple warning")
      end)
    end

    test "handles empty context" do
      capture_log(fn ->
        assert :ok = MibLogger.log_warning("Warning message", %{})
      end)
    end
  end

  describe "log_vendor_quirk/3" do
    test "logs vendor quirk handling" do
      log =
        capture_log([level: :debug], fn ->
          assert :ok =
                   MibLogger.log_vendor_quirk(
                     "CISCO-MIB",
                     "Cisco",
                     "Non-standard SEQUENCE syntax"
                   )
        end)

      assert log =~ "Vendor quirk handled" or log == ""
    end
  end

  describe "log_batch_progress/2" do
    test "logs batch compilation progress" do
      capture_log(fn ->
        assert :ok = MibLogger.log_batch_progress(7, 10)
      end)
    end

    test "handles zero total" do
      capture_log(fn ->
        assert :ok = MibLogger.log_batch_progress(0, 0)
      end)
    end

    test "handles completion" do
      capture_log(fn ->
        assert :ok = MibLogger.log_batch_progress(10, 10)
      end)
    end
  end

  describe "error type extraction" do
    test "extracts error types from different error formats" do
      errors = [
        %Error{type: :syntax_error, message: "Test"},
        %Error{type: :syntax_error, message: "Test2"},
        %Error{type: :semantic_error, message: "Test3"},
        %{type: :custom_error},
        :atom_error,
        "string error",
        123
      ]

      # This tests the private extract_error_type function indirectly
      log =
        capture_log(fn ->
          assert :ok = MibLogger.log_compilation_failed("/test.mib", errors)
        end)

      assert log =~ "MIB compilation failed"
    end
  end

  describe "return values" do
    test "all logging functions return :ok" do
      # Verify return values without log capture
      assert :ok = MibLogger.log_compilation_start("/test.mib", [])
      assert :ok = MibLogger.log_compilation_success("TEST", "/output")
      assert :ok = MibLogger.log_compilation_error("TEST", [])
      assert :ok = MibLogger.log_compilation_warning("TEST", "/output", [])
      assert :ok = MibLogger.log_batch_compilation_start(5)
      assert :ok = MibLogger.log_batch_compilation_success(5)
      assert :ok = MibLogger.log_batch_compilation_error(3, 2)
      assert :ok = MibLogger.log_compilation_complete("TEST", %{})
      assert :ok = MibLogger.log_compilation_failed("/test.mib", [])
      assert :ok = MibLogger.log_parse_progress("phase", 0)
      assert :ok = MibLogger.log_import_resolution("TEST", [])
      assert :ok = MibLogger.log_imports_resolved("TEST", 0, 0)
      assert :ok = MibLogger.log_codegen("TEST", 0, 0)
      assert :ok = MibLogger.log_tokenization("TEST", 0, 0)
      assert :ok = MibLogger.log_dependency_order([])
      assert :ok = MibLogger.log_performance("phase", [])
      assert :ok = MibLogger.log_warning("message")
      assert :ok = MibLogger.log_vendor_quirk("TEST", "Vendor", "quirk")
      assert :ok = MibLogger.log_batch_progress(0, 0)
    end
  end
end
