"""
Test Output Formatting for Database Query CLI - Issue #14

This test validates the multiple output format support for database query
commands, ensuring users can get results in their preferred format.

Requirements tested:
- Table format output (human-readable)
- JSON format output (machine-readable)
- YAML format output (configuration-friendly)
- Format validation and error handling
- Consistent formatting across all commands
"""

import pytest
import json
import yaml
from click.testing import CliRunner
from unittest.mock import patch, MagicMock

# Import the CLI module (will be extended during implementation)
from markitect.cli import cli


class TestOutputFormatting:
    """Test suite for output formatting functionality."""

    def setup_method(self):
        """Set up test fixtures."""
        self.runner = CliRunner()
        self.sample_data = [
            {
                'id': 1,
                'filename': 'document1.md',
                'created_at': '2025-09-25 10:00:00',
                'front_matter': '{"title": "First Document", "author": "John Doe"}'
            },
            {
                'id': 2,
                'filename': 'document2.md',
                'created_at': '2025-09-25 11:00:00',
                'front_matter': '{"title": "Second Document", "author": "Jane Smith"}'
            }
        ]

    def test_table_format_output(self):
        """
        Test that table format produces human-readable output.

        Issue #14: Multiple output format support
        """
        with patch('markitect.cli.DatabaseManager') as mock_db_mgr:
            mock_db_instance = MagicMock()
            mock_db_mgr.return_value = mock_db_instance
            mock_db_instance.execute_query.return_value = self.sample_data

            result = self.runner.invoke(cli, [
                'db-query', 'SELECT * FROM markdown_files',
                '--format', 'table'
            ])

            assert result.exit_code == 0

            # Table format should include column headers and data
            assert 'filename' in result.output
            assert 'document1.md' in result.output
            assert 'document2.md' in result.output

            # Should have some kind of visual structure (lines, spacing, etc.)
            output_lines = result.output.split('\n')
            assert len(output_lines) >= 3  # At least header + 2 data rows



    def test_default_format_is_table(self):
        """
        Test that default output format is table when not specified.

        Issue #14: Multiple output format support
        """
        with patch('markitect.cli.DatabaseManager') as mock_db_mgr:
            mock_db_instance = MagicMock()
            mock_db_mgr.return_value = mock_db_instance
            mock_db_instance.execute_query.return_value = self.sample_data

            # Without specifying format
            result = self.runner.invoke(cli, ['db-query', 'SELECT * FROM markdown_files'])

            if result.exit_code != 0:
                print("Command output:", result.output)
                print("Command exception:", result.exception)
            assert result.exit_code == 0
            # Should look like table format (not JSON or YAML)
            assert not result.output.strip().startswith('[')  # Not JSON array
            assert not result.output.strip().startswith('-')  # Not YAML array

    def test_invalid_format_handling(self):
        """
        Test that invalid format specifications are handled gracefully.

        Issue #14: Multiple output format support
        """
        result = self.runner.invoke(cli, [
            'db-query', 'SELECT * FROM markdown_files',
            '--format', 'invalid_format'
        ])

        # Should either use default format or show error
        assert result.exit_code != 0 or 'invalid' in result.output.lower()



class TestSchemaFormatting:
    """Test suite for schema command output formatting."""

    def setup_method(self):
        """Set up test fixtures."""
        self.runner = CliRunner()
        self.schema_data = {
            'markdown_files': {
                'columns': [
                    {'name': 'id', 'type': 'INTEGER', 'primary_key': True, 'nullable': False},
                    {'name': 'filename', 'type': 'TEXT', 'primary_key': False, 'nullable': False},
                    {'name': 'front_matter', 'type': 'TEXT', 'primary_key': False, 'nullable': True},
                    {'name': 'content', 'type': 'TEXT', 'primary_key': False, 'nullable': True},
                    {'name': 'created_at', 'type': 'TIMESTAMP', 'primary_key': False, 'nullable': True}
                ]
            }
        }

    def test_schema_table_format(self):
        """
        Test that schema command produces readable table format.

        Issue #14: Schema inspection commands
        """
        with patch('markitect.cli.DatabaseManager') as mock_db_mgr:
            mock_db_instance = MagicMock()
            mock_db_mgr.return_value = mock_db_instance
            mock_db_instance.get_schema.return_value = self.schema_data

            result = self.runner.invoke(cli, ['db-schema', '--format', 'table'])

            assert result.exit_code == 0
            assert 'markdown_files' in result.output
            assert 'filename' in result.output
            assert 'INTEGER' in result.output
            assert 'TEXT' in result.output


    def test_schema_yaml_format(self):
        """
        Test that schema command produces valid YAML format.

        Issue #14: Schema inspection commands
        """
        with patch('markitect.cli.DatabaseManager') as mock_db_mgr:
            mock_db_instance = MagicMock()
            mock_db_mgr.return_value = mock_db_instance
            mock_db_instance.get_schema.return_value = self.schema_data

            result = self.runner.invoke(cli, ['db-schema', '--format', 'yaml'])

            assert result.exit_code == 0
            try:
                parsed = yaml.safe_load(result.output)
                assert 'markdown_files' in parsed
                assert 'columns' in parsed['markdown_files']
            except yaml.YAMLError:
                pytest.fail("Schema YAML output should be valid YAML")


class TestDbDataFormatting:
    """Test suite for db-data command output formatting."""

    def setup_method(self):
        """Set up test fixtures."""
        self.runner = CliRunner()
        self.metadata = {
            'id': 1,
            'filename': 'test.md',
            'front_matter': '{"title": "Test Document", "author": "Test Author", "tags": ["test", "demo"]}',
            'content': '# Test Document\n\nThis is test content.',
            'created_at': '2025-09-25 12:00:00'
        }

    def test_db_data_table_format(self):
        """
        Test that db-data command produces readable table format.

        Issue #14: Metadata display functionality (updated for Issue #38)
        """
        with patch('markitect.cli.DatabaseManager') as mock_db_mgr:
            mock_db_instance = MagicMock()
            mock_db_mgr.return_value = mock_db_instance
            mock_db_instance.get_markdown_file.return_value = self.metadata

            result = self.runner.invoke(cli, ['db-data', 'test.md', '--format', 'table'])

            assert result.exit_code == 0
            assert 'test.md' in result.output
            assert 'Test Document' in result.output
            assert 'Test Author' in result.output

    def test_db_data_json_format(self):
        """
        Test that db-data command produces valid JSON format.

        Issue #14: Metadata display functionality (updated for Issue #38)
        """
        with patch('markitect.cli.DatabaseManager') as mock_db_mgr:
            mock_db_instance = MagicMock()
            mock_db_mgr.return_value = mock_db_instance
            mock_db_instance.get_markdown_file.return_value = self.metadata

            result = self.runner.invoke(cli, ['db-data', 'test.md', '--format', 'json'])

            assert result.exit_code == 0
            try:
                parsed = json.loads(result.output.strip())
                assert parsed['filename'] == 'test.md'
                assert 'front_matter' in parsed
            except json.JSONDecodeError:
                pytest.fail("Metadata JSON output should be valid JSON")

    def test_db_data_yaml_format(self):
        """
        Test that db-data command produces valid YAML format.

        Issue #14: Metadata display functionality (updated for Issue #38)
        """
        with patch('markitect.cli.DatabaseManager') as mock_db_mgr:
            mock_db_instance = MagicMock()
            mock_db_mgr.return_value = mock_db_instance
            mock_db_instance.get_markdown_file.return_value = self.metadata

            result = self.runner.invoke(cli, ['db-data', 'test.md', '--format', 'yaml'])

            assert result.exit_code == 0
            try:
                parsed = yaml.safe_load(result.output)
                assert parsed['filename'] == 'test.md'
                assert 'front_matter' in parsed
            except yaml.YAMLError:
                pytest.fail("Metadata YAML output should be valid YAML")


class TestFormattingConsistency:
    """Test suite for formatting consistency across commands."""

    def setup_method(self):
        """Set up test fixtures."""
        self.runner = CliRunner()

    def test_format_option_consistency(self):
        """
        Test that --format option works consistently across all commands.

        Issue #14: Multiple output format support
        """
        commands = [
            ['db-query', 'SELECT COUNT(*) FROM markdown_files'],
            ['db-schema'],
            ['metadata', 'test.md']
        ]

        formats = ['table', 'json', 'yaml']

        for command in commands:
            for fmt in formats:
                # Test that all commands accept the format option
                result = self.runner.invoke(cli, command + ['--format', fmt, '--help'])
                # Should not error on the format option itself
                assert 'unrecognized arguments' not in result.output.lower()

    def test_format_error_consistency(self):
        """
        Test that format errors are handled consistently across commands.

        Issue #14: Multiple output format support
        """
        commands = [
            ['db-query', 'SELECT COUNT(*) FROM markdown_files'],
            ['db-schema'],
            ['metadata', 'test.md']
        ]

        for command in commands:
            result = self.runner.invoke(cli, command + ['--format', 'invalid'])
            # Should either reject invalid format or use default
            # Consistent error handling across all commands
            assert result.exit_code == 0 or 'invalid' in result.output.lower()


class TestFormattingUtilities:
    """Test suite for formatting utility functions."""

    def test_format_table_utility(self):
        """
        Test table formatting utility function.

        Issue #14: Multiple output format support
        """
        # This test will validate the internal table formatting function
        # once it's implemented in the CLI module

        sample_data = [
            {'name': 'file1.md', 'size': 100},
            {'name': 'file2.md', 'size': 200}
        ]

        # Test that we can format data as a table
        # The actual implementation will depend on the formatting utility chosen
        assert isinstance(sample_data, list)  # Basic validation for now

    def test_format_json_utility(self):
        """
        Test JSON formatting utility function.

        Issue #14: Multiple output format support
        """
        sample_data = [{'name': 'test.md', 'id': 1}]

        # Should be able to serialize to JSON
        json_output = json.dumps(sample_data, indent=2)
        assert 'test.md' in json_output
        assert isinstance(json.loads(json_output), list)

    def test_format_yaml_utility(self):
        """
        Test YAML formatting utility function.

        Issue #14: Multiple output format support
        """
        sample_data = [{'name': 'test.md', 'id': 1}]

        # Should be able to serialize to YAML
        yaml_output = yaml.dump(sample_data, default_flow_style=False)
        assert 'test.md' in yaml_output
        assert isinstance(yaml.safe_load(yaml_output), list)