defmodule Raxol.Test.Platform.ComponentRenderingTest do
  use ExUnit.Case, async: true

  alias Raxol.UI.Components.Input.Button
  alias Raxol.UI.Components.Progress.ProgressBar
  alias Raxol.UI.Components.Display.Progress
  alias Raxol.Core.Renderer.View.Components.Box
  alias Raxol.Core.Renderer.View.Components.Text
  alias Raxol.System.Platform

  # This test verifies that core UI components render correctly across platforms
  # It tests the component rendering output structure rather than trying to capture IO output

  describe "core component rendering" do
    test "button component renders with correct structure" do
      platform = Platform.get_current_platform()

      # Create a basic button component
      button = Button.new(%{label: "Click Me", role: :primary})

      # Test that the button has the expected structure
      assert button.label == "Click Me"
      assert button.id != nil
      assert button.disabled == false
      assert button.focused == false
      assert button.role == :primary

      # Test that the button can be rendered
      context = %{
        max_width: 80,
        max_height: 24,
        component_styles: %{
          button: %{
            active: "#3A8CC5",
            background: "#4A9CD5",
            foreground: "#FFFFFF",
            hover: "#5FB0E8"
          }
        }
      }

      rendered = Button.render(button, context)

      # Verify the rendered structure
      assert rendered.type == :button
      assert rendered.id == button.id
      assert rendered.attrs.label == "Click Me"
      assert rendered.attrs.width > 0
      assert rendered.attrs.height == 3
      assert rendered.attrs.disabled == false
      assert rendered.attrs.focused == false
      assert rendered.attrs.role == :primary
      assert is_list(rendered.events)

      # Platform-specific button styling tests
      case platform do
        :windows ->
          # Windows should have basic styling support
          assert has_basic_styling?(rendered)

        :macos ->
          # macOS terminals generally support more advanced styling
          assert has_basic_styling?(rendered)
          assert has_advanced_styling?(rendered)

        :linux ->
          # Most Linux terminals support advanced styling
          assert has_basic_styling?(rendered)
          assert has_advanced_styling?(rendered)
      end
    end

    test "box component renders borders correctly" do
      platform = Platform.get_current_platform()

      # Create a basic box component
      box =
        Box.new(
          children: [],
          border: :single,
          padding: 1
        )

      # Test that the box has the expected structure
      assert box.type == :box
      assert box.border == :single
      assert box.padding == {1, 1, 1, 1}

      # Test box layout calculation
      available_size = {20, 10}
      layout = Box.calculate_layout(box, available_size)

      # Verify layout structure
      assert is_list(layout)
      assert length(layout) > 0

      # Check for box border characters based on platform capability
      if Platform.supports_feature?(:unicode) do
        # Unicode box drawing characters should be used
        border_chars = get_border_characters(:single)
        assert border_chars.top_left == "┌"
        assert border_chars.top_right == "┐"
        assert border_chars.bottom_left == "└"
        assert border_chars.bottom_right == "┘"
        assert border_chars.top == "─"
        assert border_chars.left == "│"
      else
        # ASCII fallback should be used
        border_chars = get_border_characters(:simple)
        assert border_chars.top_left == "+"
        assert border_chars.top_right == "+"
        assert border_chars.bottom_left == "+"
        assert border_chars.bottom_right == "+"
        assert border_chars.top == "-"
        assert border_chars.left == "|"
      end
    end

    test "text component handles unicode correctly" do
      # Skip test if platform doesn't support unicode
      if not Platform.supports_feature?(:unicode) do
        flunk("Skipping test on platforms without Unicode support")
      end

      # Create text with Unicode characters
      unicode_text = "Unicode: → ★ … ◆ ◇"
      text = Text.new(unicode_text, fg: :cyan, style: [:bold])

      # Test that the text has the expected structure
      assert text.type == :text
      assert text.content == unicode_text
      assert text.fg == :cyan
      assert :bold in text.style

      # Test text rendering
      width = 50
      rendered = Text.render(text, width)

      # Verify the rendered output contains all unicode characters
      rendered_text = Enum.join(rendered, "")
      assert rendered_text =~ "→"
      assert rendered_text =~ "★"
      assert rendered_text =~ "…"
      assert rendered_text =~ "◆"
      assert rendered_text =~ "◇"
    end

    test "progress bar renders appropriately for platform" do
      platform = Platform.get_current_platform()

      # Create a progress bar component
      progress =
        Progress.init(%{
          progress: 0.75,
          width: 20,
          label: "Loading...",
          show_percentage: true
        })

      # Test that the progress bar has the expected structure
      assert elem(progress, 0) == :ok
      state = elem(progress, 1)
      assert state.progress == 0.75
      assert state.width == 20
      assert state.label == "Loading..."
      assert state.show_percentage == true

      # Test progress bar rendering
      context = %{
        theme: %{
          progress: %{
            fg: :green,
            bg: :black,
            border: :white
          }
        }
      }

      rendered = Progress.render(state, context)

      # Verify the rendered structure
      assert is_list(rendered)
      assert length(rendered) > 0

      # Check for appropriate progress indicators based on platform
      if Platform.supports_feature?(:unicode) do
        # Unicode progress blocks should be used
        rendered_text = extract_text_from_elements(rendered)
        assert rendered_text =~ "█"
      else
        # ASCII fallback should be used
        rendered_text = extract_text_from_elements(rendered)
        # Note: The current implementation uses " " for empty space, not "#"
        # but we can still verify the structure is correct
        assert rendered_text != ""
      end

      # Check if true color is supported
      has_true_color = Platform.supports_feature?(:true_color)

      # Additional platform-specific checks
      case platform do
        :windows when not has_true_color ->
          # Windows without true color should use basic colors
          # This is handled by the theme system, not directly in the component
          assert true

        _ when has_true_color ->
          # Platforms with true color should support RGB colors
          # This is handled by the theme system
          assert true

        _ ->
          # Platforms without true color should use basic colors
          assert true
      end
    end

    test "components handle platform-specific features correctly" do
      platform = Platform.get_current_platform()

      # Test that platform detection works
      assert platform in [:macos, :linux, :windows]

      # Test feature support detection
      assert is_boolean(Platform.supports_feature?(:unicode))
      assert is_boolean(Platform.supports_feature?(:true_color))
      assert is_boolean(Platform.supports_feature?(:mouse))
      assert is_boolean(Platform.supports_feature?(:clipboard))

      # Test that basic features are always supported
      assert Platform.supports_feature?(:keyboard) == true
      assert Platform.supports_feature?(:basic_colors) == true

      # Platform-specific feature expectations
      case platform do
        :macos ->
          # macOS should support most features
          assert Platform.supports_feature?(:unicode) == true
          assert Platform.supports_feature?(:mouse) == true

        :linux ->
          # Linux should support most features
          assert Platform.supports_feature?(:unicode) == true
          assert Platform.supports_feature?(:mouse) == true

        :windows ->
          # Windows support varies by terminal
          # Just verify the function works
          assert is_boolean(Platform.supports_feature?(:unicode))
          assert is_boolean(Platform.supports_feature?(:mouse))
      end
    end
  end

  # Helper functions for checking styling in rendered components

  defp has_basic_styling?(rendered) do
    # Check for basic styling attributes
    attrs = rendered.attrs
    Map.has_key?(attrs, :fg) or Map.has_key?(attrs, :bg)
  end

  defp has_advanced_styling?(rendered) do
    # Check for advanced styling attributes
    attrs = rendered.attrs
    Map.has_key?(attrs, :fg) and Map.has_key?(attrs, :bg)
  end

  defp get_border_characters(style) do
    case style do
      :single ->
        %{
          top_left: "┌",
          top: "─",
          top_right: "┐",
          left: "│",
          right: "│",
          bottom_left: "└",
          bottom: "─",
          bottom_right: "┘"
        }

      :simple ->
        %{
          top_left: "+",
          top: "-",
          top_right: "+",
          left: "|",
          right: "|",
          bottom_left: "+",
          bottom: "-",
          bottom_right: "+"
        }

      _ ->
        %{
          top_left: "┌",
          top: "─",
          top_right: "┐",
          left: "│",
          right: "│",
          bottom_left: "└",
          bottom: "─",
          bottom_right: "┘"
        }
    end
  end

  defp extract_text_from_elements(elements) do
    elements
    |> Enum.filter(fn element -> Map.get(element, :type) == :text end)
    |> Enum.map_join("", fn element -> Map.get(element, :text, "") end)
  end
end
