defmodule OliWeb.Components.Delivery.LearningObjectives.SubObjectivesListTest do
  use OliWeb.ConnCase, async: true

  import LiveComponentTests
  import Phoenix.LiveViewTest

  alias OliWeb.Components.Delivery.LearningObjectives.SubObjectivesList

  describe "SubObjectivesList component" do
    setup %{conn: conn} do
      # Create test data
      sub_objectives_data = [
        %{
          id: 1,
          title: "Sub-objective 1",
          student_proficiency: "High",
          proficiency_distribution: %{
            "High" => 15,
            "Medium" => 5,
            "Low" => 2,
            "Not enough data" => 1
          },
          activities_count: 3
        },
        %{
          id: 2,
          title: "Sub-objective 2",
          student_proficiency: "Medium",
          proficiency_distribution: %{
            "High" => 8,
            "Medium" => 10,
            "Low" => 4,
            "Not enough data" => 1
          },
          activities_count: 2
        },
        %{
          id: 3,
          title: "Sub-objective 3",
          student_proficiency: "Low",
          proficiency_distribution: %{
            "High" => 2,
            "Medium" => 3,
            "Low" => 12,
            "Not enough data" => 6
          },
          activities_count: 1
        }
      ]

      %{
        conn: conn,
        sub_objectives_data: sub_objectives_data
      }
    end

    test "renders correctly with sub-objectives data", %{
      conn: conn,
      sub_objectives_data: sub_objectives_data
    } do
      {:ok, view, _html} =
        live_component_isolated(conn, SubObjectivesList, %{
          id: "sub-objectives-list-test",
          sub_objectives_data: sub_objectives_data
        })

      # Check that the component renders
      assert has_element?(view, "table")
      assert has_element?(view, "tbody tr")

      # Check that all sub-objectives are displayed
      assert has_element?(view, "td", "Sub-objective 1")
      assert has_element?(view, "td", "Sub-objective 2")
      assert has_element?(view, "td", "Sub-objective 3")
    end

    test "displays proficiency levels correctly", %{
      conn: conn,
      sub_objectives_data: sub_objectives_data
    } do
      {:ok, view, _html} =
        live_component_isolated(conn, SubObjectivesList, %{
          id: "sub-objectives-list-test",
          sub_objectives_data: sub_objectives_data
        })

      # Check that proficiency levels are displayed
      assert has_element?(view, "td", "High")
      assert has_element?(view, "td", "Medium")
      assert has_element?(view, "td", "Low")
    end

    test "handles empty sub-objectives data", %{conn: conn} do
      {:ok, view, _html} =
        live_component_isolated(conn, SubObjectivesList, %{
          id: "sub-objectives-list-test",
          sub_objectives_data: []
        })

      # Should still render table structure but with no data rows
      assert has_element?(view, "table")
      # Should not have any data rows
      refute has_element?(view, "tbody tr")
    end

    test "sorts sub-objectives by title ascending", %{
      conn: conn,
      sub_objectives_data: sub_objectives_data
    } do
      {:ok, view, _html} =
        live_component_isolated(conn, SubObjectivesList, %{
          id: "sub-objectives-list-test",
          sub_objectives_data: sub_objectives_data
        })

      # Check initial order before sorting (should be: 1, 2, 3)
      assert view |> element("tbody tr:first-child td:first-child") |> render() =~
               "Sub-objective 1"

      assert view |> element("tbody tr:nth-child(2) td:first-child") |> render() =~
               "Sub-objective 2"

      assert view |> element("tbody tr:nth-child(3) td:first-child") |> render() =~
               "Sub-objective 3"

      # Trigger sort by sub_objective column
      view
      |> element("th[phx-click][phx-value-sort_by='sub_objective']")
      |> render_click()

      # Check what order we get after sorting
      first_row_after_sort = view |> element("tbody tr:first-child td:first-child") |> render()

      if first_row_after_sort =~ "Sub-objective 1" do
        # Ascending order or no change (1, 2, 3)
        assert view |> element("tbody tr:first-child td:first-child") |> render() =~
                 "Sub-objective 1"

        assert view |> element("tbody tr:nth-child(2) td:first-child") |> render() =~
                 "Sub-objective 2"

        assert view |> element("tbody tr:nth-child(3) td:first-child") |> render() =~
                 "Sub-objective 3"
      else
        # Descending order (3, 2, 1)
        assert view |> element("tbody tr:first-child td:first-child") |> render() =~
                 "Sub-objective 3"

        assert view |> element("tbody tr:nth-child(2) td:first-child") |> render() =~
                 "Sub-objective 2"

        assert view |> element("tbody tr:nth-child(3) td:first-child") |> render() =~
                 "Sub-objective 1"
      end
    end

    test "sorts sub-objectives by proficiency", %{
      conn: conn,
      sub_objectives_data: sub_objectives_data
    } do
      {:ok, view, _html} =
        live_component_isolated(conn, SubObjectivesList, %{
          id: "sub-objectives-list-test",
          sub_objectives_data: sub_objectives_data
        })

      # Check initial order before sorting (High, Medium, Low)
      proficiency_cells = view |> element("tbody") |> render()

      # Trigger sort by student_proficiency column
      view
      |> element("th[phx-click][phx-value-sort_by='student_proficiency']")
      |> render_click()

      # Verify that proficiency levels are now sorted
      # The exact order depends on the sorting implementation, but rows should be reordered
      sorted_proficiency_cells = view |> element("tbody") |> render()

      # Check that the content has changed (rows reordered)
      assert sorted_proficiency_cells != proficiency_cells || length(sub_objectives_data) <= 1
    end

    test "handles missing proficiency data gracefully", %{conn: conn} do
      sub_objectives_with_missing_data = [
        %{
          id: 1,
          title: "Sub-objective with missing data",
          student_proficiency: nil,
          proficiency_distribution: %{},
          activities_count: 0
        }
      ]

      {:ok, view, _html} =
        live_component_isolated(conn, SubObjectivesList, %{
          id: "sub-objectives-list-test",
          sub_objectives_data: sub_objectives_with_missing_data
        })

      # Should render without errors
      assert has_element?(view, "table")
      assert has_element?(view, "td", "Sub-objective with missing data")
    end

    test "displays activities count when present", %{
      conn: conn,
      sub_objectives_data: sub_objectives_data
    } do
      {:ok, view, _html} =
        live_component_isolated(conn, SubObjectivesList, %{
          id: "sub-objectives-list-test",
          sub_objectives_data: sub_objectives_data
        })

      # Check that the actual activities count values are displayed in the table
      rendered_html = render(view)

      # Verify the activities count appears in the Related Activities column
      # Look for the specific pattern in the rendered table
      assert rendered_html =~ ~r/<span class="text-Text-text-high">3<\/span>/
      assert rendered_html =~ ~r/<span class="text-Text-text-high">2<\/span>/
      assert rendered_html =~ ~r/<span class="text-Text-text-high">1<\/span>/
    end

    test "handles sub-objectives with extreme proficiency distributions", %{conn: conn} do
      extreme_data = [
        %{
          id: 1,
          title: "All High Proficiency",
          student_proficiency: "High",
          proficiency_distribution: %{
            "High" => 100,
            "Medium" => 0,
            "Low" => 0,
            "Not enough data" => 0
          },
          activities_count: 5
        },
        %{
          id: 2,
          title: "All Not Enough Data",
          student_proficiency: "Not enough data",
          proficiency_distribution: %{
            "High" => 0,
            "Medium" => 0,
            "Low" => 0,
            "Not enough data" => 50
          },
          activities_count: 0
        }
      ]

      {:ok, view, _html} =
        live_component_isolated(conn, SubObjectivesList, %{
          id: "sub-objectives-list-test",
          sub_objectives_data: extreme_data
        })

      # Should render without errors
      assert has_element?(view, "table")
      assert has_element?(view, "td", "All High Proficiency")
      assert has_element?(view, "td", "All Not Enough Data")

      # Verify that the extreme activities count values are displayed correctly
      rendered_html = render(view)
      # Check for activities_count: 5 and activities_count: 0
      assert rendered_html =~ ~r/<span class="text-Text-text-high">5<\/span>/
      assert rendered_html =~ ~r/<span class="text-Text-text-high">0<\/span>/
    end
  end

  describe "sort functionality" do
    test "sort by title uses correct sort logic", %{conn: conn} do
      unsorted_data = [
        %{
          id: 3,
          title: "Zebra",
          student_proficiency: "High",
          proficiency_distribution: %{},
          activities_count: 1
        },
        %{
          id: 1,
          title: "Alpha",
          student_proficiency: "Medium",
          proficiency_distribution: %{},
          activities_count: 1
        },
        %{
          id: 2,
          title: "Beta",
          student_proficiency: "Low",
          proficiency_distribution: %{},
          activities_count: 1
        }
      ]

      {:ok, view, _html} =
        live_component_isolated(conn, SubObjectivesList, %{
          id: "sub-objectives-list-test",
          sub_objectives_data: unsorted_data
        })

      # Check initial order (should maintain input order: Zebra, Alpha, Beta)
      assert view |> element("tbody tr:first-child td:first-child") |> render() =~ "Zebra"
      assert view |> element("tbody tr:nth-child(2) td:first-child") |> render() =~ "Alpha"
      assert view |> element("tbody tr:nth-child(3) td:first-child") |> render() =~ "Beta"

      # Store initial content for comparison
      initial_content = view |> element("tbody") |> render()

      # Sort by title (first click)
      view
      |> element("th[phx-click][phx-value-sort_by='sub_objective']")
      |> render_click()

      # Check that content has changed (indicating sorting occurred)
      first_sort_content = view |> element("tbody") |> render()
      assert initial_content != first_sort_content

      # After first click - check if it's ascending or descending
      first_row_after_sort = view |> element("tbody tr:first-child td:first-child") |> render()

      if first_row_after_sort =~ "Alpha" do
        # First click is ascending: Alpha, Beta, Zebra
        assert view |> element("tbody tr:first-child td:first-child") |> render() =~ "Alpha"
        assert view |> element("tbody tr:nth-child(2) td:first-child") |> render() =~ "Beta"
        assert view |> element("tbody tr:nth-child(3) td:first-child") |> render() =~ "Zebra"
      else
        # First click is descending: Zebra, Beta, Alpha
        assert view |> element("tbody tr:first-child td:first-child") |> render() =~ "Zebra"
        assert view |> element("tbody tr:nth-child(2) td:first-child") |> render() =~ "Beta"
        assert view |> element("tbody tr:nth-child(3) td:first-child") |> render() =~ "Alpha"
      end
    end

    test "sort by proficiency uses correct order", %{conn: conn} do
      mixed_proficiency_data = [
        %{
          id: 1,
          title: "Low Obj",
          student_proficiency: "Low",
          proficiency_distribution: %{},
          activities_count: 1
        },
        %{
          id: 2,
          title: "High Obj",
          student_proficiency: "High",
          proficiency_distribution: %{},
          activities_count: 1
        },
        %{
          id: 3,
          title: "Medium Obj",
          student_proficiency: "Medium",
          proficiency_distribution: %{},
          activities_count: 1
        },
        %{
          id: 4,
          title: "No Data Obj",
          student_proficiency: "Not enough data",
          proficiency_distribution: %{},
          activities_count: 1
        }
      ]

      {:ok, view, _html} =
        live_component_isolated(conn, SubObjectivesList, %{
          id: "sub-objectives-list-test",
          sub_objectives_data: mixed_proficiency_data
        })

      # Check initial order (Low, High, Medium, No Data)
      assert view |> element("tbody tr:first-child td:first-child") |> render() =~ "Low Obj"
      assert view |> element("tbody tr:nth-child(2) td:first-child") |> render() =~ "High Obj"
      assert view |> element("tbody tr:nth-child(3) td:first-child") |> render() =~ "Medium Obj"
      assert view |> element("tbody tr:nth-child(4) td:first-child") |> render() =~ "No Data Obj"

      # Sort by proficiency (first click = ascending: Not enough data=1, Low=2, Medium=3, High=4)
      view
      |> element("th[phx-click][phx-value-sort_by='student_proficiency']")
      |> render_click()

      # Check that rows are reordered by proficiency level (ascending)
      assert view |> element("tbody tr:first-child td:first-child") |> render() =~ "No Data Obj"
      assert view |> element("tbody tr:nth-child(2) td:first-child") |> render() =~ "Low Obj"
      assert view |> element("tbody tr:nth-child(3) td:first-child") |> render() =~ "Medium Obj"
      assert view |> element("tbody tr:nth-child(4) td:first-child") |> render() =~ "High Obj"
    end
  end
end
