defmodule UmyaSpreadsheet.DataValidationGettersTest do
  use ExUnit.Case
  alias UmyaSpreadsheet.DataValidation

  setup do
    {:ok, spreadsheet} = UmyaSpreadsheet.new()
    {:ok, %{spreadsheet: spreadsheet}}
  end

  describe "data validation getters" do
    test "get_data_validations returns correct list of validations", %{spreadsheet: spreadsheet} do
      # Set up a sheet with some validation rules
      DataValidation.add_list_validation(
        spreadsheet,
        "Sheet1",
        "A1:A5",
        ["Option 1", "Option 2", "Option 3"],
        true,
        "Invalid Selection",
        "Please select a valid option",
        "Selection Required",
        "Choose from the list"
      )

      DataValidation.add_number_validation(
        spreadsheet,
        "Sheet1",
        "B1:B5",
        "between",
        10.0,
        20.0,
        true,
        "Invalid Number",
        "Please enter a number between 10 and 20",
        nil,
        nil
      )

      # Test get_data_validations
      {:ok, validations} = DataValidation.get_data_validations(spreadsheet, "Sheet1")

      assert is_list(validations)
      assert length(validations) == 2

      # Verify that both validation types are returned
      validation_types = Enum.map(validations, & &1.rule_type)
      assert :list in validation_types
      assert :decimal in validation_types or :whole in validation_types
    end

    test "get_list_validations returns only list validations", %{spreadsheet: spreadsheet} do
      # Set up a sheet with different validation types
      DataValidation.add_list_validation(
        spreadsheet,
        "Sheet1",
        "A1:A5",
        ["Red", "Green", "Blue"],
        true,
        nil,
        nil,
        nil,
        nil
      )

      DataValidation.add_number_validation(
        spreadsheet,
        "Sheet1",
        "B1:B5",
        "between",
        5.0,
        10.0,
        true,
        nil,
        nil,
        nil,
        nil
      )

      # Test get_list_validations
      {:ok, list_validations} = DataValidation.get_list_validations(spreadsheet, "Sheet1")

      assert is_list(list_validations)
      assert length(list_validations) == 1

      # Verify that only list validations are returned
      assert Enum.all?(list_validations, &(&1.rule_type == :list))

      # Verify the list items are preserved
      list_validation = List.first(list_validations)
      assert list_validation.list_items == ["Red", "Green", "Blue"]
    end

    test "get_number_validations returns only number validations", %{spreadsheet: spreadsheet} do
      # Set up a sheet with different validation types
      DataValidation.add_list_validation(
        spreadsheet,
        "Sheet1",
        "A1:A5",
        ["Option 1", "Option 2"],
        true,
        nil,
        nil,
        nil,
        nil
      )

      DataValidation.add_number_validation(
        spreadsheet,
        "Sheet1",
        "B1:B5",
        "between",
        5.0,
        10.0,
        true,
        nil,
        nil,
        nil,
        nil
      )

      # Test get_number_validations
      {:ok, number_validations} = DataValidation.get_number_validations(spreadsheet, "Sheet1")

      assert is_list(number_validations)
      assert length(number_validations) == 1

      # Verify that only number validations are returned
      number_validation = List.first(number_validations)
      assert number_validation.rule_type in [:decimal, :whole]

      # Verify the number validation properties are preserved
      assert number_validation.value1 == "5.0"
      assert number_validation.value2 == "10.0"
      assert number_validation.allow_blank == true
    end

    test "get_date_validations returns only date validations", %{spreadsheet: spreadsheet} do
      # Set up a sheet with different validation types
      # Using Date structs to test the enhanced functionality
      DataValidation.add_date_validation(
        spreadsheet,
        "Sheet1",
        "B1:B5",
        "between",
        ~D[2023-01-01],
        ~D[2023-12-31],
        false,
        "Invalid Date",
        "Please enter a date in 2023",
        nil,
        nil
      )

      DataValidation.add_list_validation(
        spreadsheet,
        "Sheet1",
        "A1:A5",
        ["Option 1", "Option 2"],
        true,
        nil,
        nil,
        nil,
        nil
      )

      # Test get_date_validations
      {:ok, date_validations} = DataValidation.get_date_validations(spreadsheet, "Sheet1")

      assert is_list(date_validations)
      assert length(date_validations) == 1

      # Verify that only date validations are returned
      assert Enum.all?(date_validations, &(&1.rule_type == :date))

      # Verify the date validation properties are preserved
      date_validation = List.first(date_validations)
      assert date_validation.date1 == "2023-01-01"
      assert date_validation.date2 == "2023-12-31"
      assert date_validation.allow_blank == false
    end

    test "get_text_length_validations returns only text length validations", %{
      spreadsheet: spreadsheet
    } do
      # Set up a sheet with different validation types
      DataValidation.add_text_length_validation(
        spreadsheet,
        "Sheet1",
        "C1:C5",
        "lessThanOrEqual",
        50,
        nil,
        true,
        "Text Too Long",
        "Please enter text with 50 characters or less",
        "Text Length",
        "Maximum 50 characters"
      )

      DataValidation.add_list_validation(
        spreadsheet,
        "Sheet1",
        "A1:A5",
        ["Option 1", "Option 2"],
        true,
        nil,
        nil,
        nil,
        nil
      )

      # Test get_text_length_validations
      {:ok, text_validations} = DataValidation.get_text_length_validations(spreadsheet, "Sheet1")

      assert is_list(text_validations)
      assert length(text_validations) == 1

      # Verify that only text length validations are returned
      assert Enum.all?(text_validations, &(&1.rule_type == :text_length))

      # Verify the text length properties are preserved
      text_validation = List.first(text_validations)
      assert text_validation.operator == :less_than_or_equal
      assert text_validation.length1 == 50
      assert text_validation.allow_blank == true
    end

    test "get_custom_validations returns only custom formula validations", %{
      spreadsheet: spreadsheet
    } do
      # Set up a sheet with different validation types
      DataValidation.add_custom_validation(
        spreadsheet,
        "Sheet1",
        "D1:D5",
        "MOD(D1,3)=0",
        true,
        "Invalid Value",
        "Value must be divisible by 3",
        nil,
        nil
      )

      DataValidation.add_list_validation(
        spreadsheet,
        "Sheet1",
        "A1:A5",
        ["Option 1", "Option 2"],
        true,
        nil,
        nil,
        nil,
        nil
      )

      # Test get_custom_validations
      {:ok, custom_validations} = DataValidation.get_custom_validations(spreadsheet, "Sheet1")

      assert is_list(custom_validations)
      assert length(custom_validations) == 1

      # Verify that only custom validations are returned
      assert Enum.all?(custom_validations, &(&1.rule_type == :custom))

      # Verify the custom formula is preserved
      custom_validation = List.first(custom_validations)
      assert custom_validation.formula == "MOD(D1,3)=0"
      assert custom_validation.allow_blank == true
    end

    test "has_data_validations returns correct boolean", %{spreadsheet: spreadsheet} do
      # Initially there should be no validations
      {:ok, has_validation} = DataValidation.has_data_validations(spreadsheet, "Sheet1")
      refute has_validation

      # Add a validation rule
      DataValidation.add_list_validation(
        spreadsheet,
        "Sheet1",
        "A1:A5",
        ["Option 1", "Option 2"],
        true,
        nil,
        nil,
        nil,
        nil
      )

      # Now there should be validations
      {:ok, has_validation} = DataValidation.has_data_validations(spreadsheet, "Sheet1")
      assert has_validation
    end

    test "count_data_validations returns correct count", %{spreadsheet: spreadsheet} do
      # Initially there should be no validations
      {:ok, count} = DataValidation.count_data_validations(spreadsheet, "Sheet1")
      assert count == 0

      # Add validation rules
      DataValidation.add_list_validation(
        spreadsheet,
        "Sheet1",
        "A1:A5",
        ["Option 1", "Option 2"],
        true,
        nil,
        nil,
        nil,
        nil
      )

      # Now there should be one validation
      {:ok, count} = DataValidation.count_data_validations(spreadsheet, "Sheet1")
      assert count == 1

      # Add another validation rule
      DataValidation.add_number_validation(
        spreadsheet,
        "Sheet1",
        "B1:B5",
        "between",
        5.0,
        10.0,
        true,
        nil,
        nil,
        nil,
        nil
      )

      # Now there should be two validations
      {:ok, count} = DataValidation.count_data_validations(spreadsheet, "Sheet1")
      assert count == 2
    end

    test "get_data_validations with cell_range parameter filters correctly if implemented", %{
      spreadsheet: spreadsheet
    } do
      # Add several validation rules in different ranges
      DataValidation.add_list_validation(
        spreadsheet,
        "Sheet1",
        "A1:A5",
        ["Option 1", "Option 2"],
        true,
        nil,
        nil,
        nil,
        nil
      )

      DataValidation.add_number_validation(
        spreadsheet,
        "Sheet1",
        "B1:B5",
        "between",
        5.0,
        10.0,
        true,
        nil,
        nil,
        nil,
        nil
      )

      # Keep using string dates here to test both formats are supported
      DataValidation.add_date_validation(
        spreadsheet,
        "Sheet1",
        "C1:C5",
        "between",
        "2023-01-01",
        "2023-12-31",
        false,
        nil,
        nil,
        nil,
        nil
      )

      # Get all validations
      {:ok, all_validations} = DataValidation.get_data_validations(spreadsheet, "Sheet1")
      assert length(all_validations) == 3

      # Verify all validations are returned when not filtering
      validation_ranges = Enum.map(all_validations, & &1.range)
      assert "A1:A5" in validation_ranges
      assert "B1:B5" in validation_ranges
      assert "C1:C5" in validation_ranges

      # Test with cell_range parameter - filtering by exact range match
      # The current implementation filters by exact range match, not cell intersection
      {:ok, filtered_validations} =
        DataValidation.get_data_validations(spreadsheet, "Sheet1", "A1:A5")

      # Should return only the validation that exactly matches "A1:A5"
      assert is_list(filtered_validations)
      assert length(filtered_validations) == 1
      assert List.first(filtered_validations).range == "A1:A5"
      assert List.first(filtered_validations).rule_type == :list

      # Test with a range that doesn't match any validation
      {:ok, no_match_validations} =
        DataValidation.get_data_validations(spreadsheet, "Sheet1", "Z1:Z5")

      assert length(no_match_validations) == 0

      # Test with another exact range match
      {:ok, number_validations} =
        DataValidation.get_data_validations(spreadsheet, "Sheet1", "B1:B5")

      assert length(number_validations) == 1
      assert List.first(number_validations).range == "B1:B5"
      assert List.first(number_validations).rule_type in [:decimal, :whole]
    end
  end
end
