"""Tests for flexible option ordering functionality."""

import pytest

from freyja import FreyjaCLI


class SampleClassForOrdering:
  """Sample class for flexible ordering tests."""

  def __init__(self, config_file: str = "config.json", debug: bool = False, timeout: int = 30):
    """Initialize with global configuration options."""
    self.config_file = config_file
    self.debug = debug
    self.timeout = timeout

  def process_data(self, data: str = "test", format_type: str = "json", validate: bool = True):
    """Process data with various options.

    :param data: Data to process
    :param format_type: Data format
    :param validate: Enable validation
    """
    result = f"Processing: {data} (format: {format_type}, config: {self.config_file})"
    if self.debug:
      result += " [DEBUG]"
    if validate:
      result += " [VALIDATED]"
    return result

  def simple_action(self, message: str = "hello"):
    """Simple action for testing.

    :param message: Message to display
    """
    return f"Action: {message} (timeout: {self.timeout})"


class SampleClassWithInnerClassOrdering:
  """Sample class with inner classes for hierarchical flexible ordering tests."""

  def __init__(self, base_config: str = "base.json", log_level: str = "INFO"):
    """Initialize with global options."""
    self.base_config = base_config
    self.log_level = log_level

  class DatabaseOps:
    """Database operations with sub-global options."""

    def __init__(self, connection_string: str = "sqlite:///test.db", pool_size: int = 5):
      """Initialize database operations."""
      self.connection_string = connection_string
      self.pool_size = pool_size

    def query_data(self, table_name: str, limit: int = 100, order_by: str = "id"):
      """Query data from table.

      :param table_name: Table to query
      :param limit: Result limit
      :param order_by: Order by field
      """
      return f"Query {table_name}: limit={limit}, order={order_by}, pool={self.pool_size}, conn={self.connection_string}"

    def migrate_schema(self, version: str = "latest"):
      """Migrate database schema.

      :param version: Target version
      """
      return f"Migrating to {version} (conn: {self.connection_string})"

  class FileOps:
    """File operations with different sub-global options."""

    def __init__(self, working_dir: str = "./data", backup_enabled: bool = True):
      """Initialize file operations."""
      self.working_dir = working_dir
      self.backup_enabled = backup_enabled

    def process_file(self, filename: str, output_format: str = "json"):
      """Process a file.

      :param filename: File to process
      :param output_format: Output format
      """
      backup_status = "with backup" if self.backup_enabled else "no backup"
      return f"Processing {filename} -> {output_format} in {self.working_dir} ({backup_status})"




class TestFlexibleOrderingClassBased:
  """Test flexible ordering with class-based CLIs."""

  def test_global_options_at_end_class(self):
    """Test global options at end for class CLI."""
    cli = FreyjaCLI(SampleClassForOrdering, "Class CLI")

    # Global config option at end
    result = cli.run(['process-data', '--data', 'test123', '--config-file', 'prod.json'])
    assert "Processing: test123" in result
    assert "config: prod.json" in result

  def test_global_options_mixed_with_command_options(self):
    """Test global options mixed with command options."""
    cli = FreyjaCLI(SampleClassForOrdering, "Class CLI")

    # Mix global and command options in various positions
    result = cli.run([
      'process-data',
      '--debug',           # global option
      '--data', 'mixed_test',  # command option
      '--timeout', '60',   # global option
      '--format-type', 'xml'   # command option
    ])
    assert "Processing: mixed_test" in result
    assert "format: xml" in result
    assert "[DEBUG]" in result

  def test_all_global_options_at_end(self):
    """Test multiple global options all at the end."""
    cli = FreyjaCLI(SampleClassForOrdering, "Class CLI")

    result = cli.run([
      'simple-action',
      '--message', 'test_message',
      '--debug',           # global
      '--timeout', '120',  # global
      '--config-file', 'special.json'  # global
    ])
    assert "Action: test_message" in result
    assert "timeout: 120" in result




class TestFlexibleOrderingWithPositional:
  """Test flexible ordering combined with positional parameters."""




class TestFlexibleOrderingErrorHandling:
  """Test error handling with flexible ordering."""

  def test_unknown_options_still_caught(self):
    """Test that unknown options are still caught with flexible ordering."""
    cli = FreyjaCLI(SampleClassForOrdering, "Test CLI")

    # Unknown option should still cause error regardless of position
    with pytest.raises(SystemExit):
      cli.run(['process-data', '--unknown-option', 'value'])

  # missing required 'text'

  def test_invalid_option_values_still_caught(self):
    """Test that invalid option values are still caught."""
    cli = FreyjaCLI(SampleClassForOrdering, "Test CLI")

    # Invalid integer value should still cause error
    with pytest.raises(SystemExit):
      cli.run(['process-data', '--timeout', 'not_a_number'])


class TestFlexibleOrderingCompatibility:
  """Test backward compatibility with existing CLI patterns."""

  def test_traditional_ordering_still_works(self):
    """Test that traditional option ordering still works perfectly."""
    cli = FreyjaCLI(SampleClassForOrdering, "Test CLI")

    # Traditional ordering: global -> command -> command options
    result = cli.run([
      '--config-file', 'traditional.json',
      '--debug',
      'process-data',
      '--data', 'traditional_test',
      '--format-type', 'yaml'
    ])
    assert "Processing: traditional_test" in result
    assert "format: yaml" in result
    assert "config: traditional.json" in result
    assert "[DEBUG]" in result

  def test_help_system_unaffected(self):
    """Test that help system works normally with flexible ordering."""
    cli = FreyjaCLI(SampleClassForOrdering, "Test CLI")
    parser = cli.create_parser()

    # Help should work normally
    help_text = parser.format_help()
    assert "Test CLI" in help_text
    assert "process-data" in help_text
    assert "simple-action" in help_text

  def test_completion_system_unaffected(self):
    """Test that completion system works with flexible ordering."""
    cli = FreyjaCLI(SampleClassForOrdering, "Test CLI", completion=True)

    # Should create successfully with completion
    assert cli.enable_completion is True

    # Should still work normally with flexible ordering
    result = cli.run(['simple-action', '--config-file', 'comp.json'])
    assert "Action: hello" in result


class TestFlexibleOrderingEdgeCases:
  """Test edge cases for flexible ordering."""

  def test_option_value_pairs_stay_together(self):
    """Test that option-value pairs are kept together during reordering."""
    cli = FreyjaCLI(SampleClassForOrdering, "Test CLI")

    # Options with values should stay together
    result = cli.run([
      'process-data',
      '--data', 'edge_case_data',      # command option-value pair
      '--config-file', 'edge.json',    # global option-value pair
      '--format-type', 'csv',          # command option-value pair
      '--timeout', '45'                # global option-value pair
    ])
    assert "Processing: edge_case_data" in result
    assert "format: csv" in result
    assert "config: edge.json" in result

  def test_boolean_flags_flexible_positioning(self):
    """Test boolean flags work in flexible positions."""
    cli = FreyjaCLI(SampleClassForOrdering, "Test CLI")

    # Boolean flags at various positions
    result = cli.run([
      'process-data',
      '--debug',        # global boolean flag
      '--data', 'bool_test',
      '--validate'      # command boolean flag at end
    ])
    assert "Processing: bool_test" in result
    assert "[DEBUG]" in result
    assert "[VALIDATED]" in result

  def test_empty_argument_list_handling(self):
    """Test handling of empty or minimal argument lists."""
    cli = FreyjaCLI(SampleClassForOrdering, "Test CLI")

    # Should work with minimal arguments
    result = cli.run(['simple-action'])
    assert "Action: hello" in result
    assert "timeout: 30" in result

  def test_only_global_options(self):
    """Test commands with only global options work."""
    cli = FreyjaCLI(SampleClassForOrdering, "Test CLI")

    # Command with only global options
    result = cli.run(['simple-action', '--config-file', 'global_only.json', '--debug'])
    assert "Action: hello" in result


class TestFlexibleOrderingComplexScenarios:
  """Test complex real-world scenarios with flexible ordering."""

