"""
Test Output Formatting for New Database Commands - Clean Implementation

This test validates the multiple output format support for the new db-prefixed
database commands, ensuring users can get results in their preferred format
without any legacy interface dependencies.

Requirements tested:
- db-query command with table, JSON, YAML format output
- db-schema command with table, JSON, YAML format output
- Format validation and error handling
- Empty result formatting across all formats
- Clean implementation without legacy interface pollution
"""

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

from markitect.cli import cli


class TestDbQueryOutputFormatting:
    """Test suite for db-query command output formatting."""

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

    def test_db_query_table_format_output(self):
        """
        Test that db-query with table format produces human-readable output.

        Clean implementation using new db-query command only.
        """
        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_db_query_json_format_output(self):
        """
        Test that db-query with JSON format produces valid JSON output.

        Clean implementation using new db-query command only.
        """
        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', 'json'
            ])

            assert result.exit_code == 0

            # Output should be valid JSON
            try:
                parsed_json = json.loads(result.output.strip())
                assert isinstance(parsed_json, list)
                assert len(parsed_json) == 2
                assert parsed_json[0]['filename'] == 'document1.md'
                assert parsed_json[1]['filename'] == 'document2.md'
            except json.JSONDecodeError:
                pytest.fail(f"Output should be valid JSON. Got: {repr(result.output)}")

    def test_db_query_yaml_format_output(self):
        """
        Test that db-query with YAML format produces valid YAML output.

        Clean implementation using new db-query command only.
        """
        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', 'yaml'
            ])

            assert result.exit_code == 0

            # Output should be valid YAML
            try:
                parsed_yaml = yaml.safe_load(result.output)
                assert isinstance(parsed_yaml, list)
                assert len(parsed_yaml) == 2
                assert parsed_yaml[0]['filename'] == 'document1.md'
                assert parsed_yaml[1]['filename'] == 'document2.md'
            except yaml.YAMLError:
                pytest.fail(f"Output should be valid YAML. Got: {repr(result.output)}")

    def test_db_query_default_format_is_table(self):
        """
        Test that db-query default output format is table when not specified.

        Clean implementation using new db-query command only.
        """
        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'])

            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_db_query_empty_result_formatting(self):
        """
        Test that db-query handles empty results correctly in all formats.

        Clean implementation using new db-query command only.
        """
        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 = []

            # Test JSON format with empty results
            result = self.runner.invoke(cli, [
                'db-query', 'SELECT * FROM markdown_files WHERE id = -1',
                '--format', 'json'
            ])
            assert result.exit_code == 0
            try:
                parsed = json.loads(result.output.strip())
                assert parsed == []
            except json.JSONDecodeError:
                # Might show "No results" message instead
                assert 'no results' in result.output.lower()

            # Test YAML format with empty results
            result = self.runner.invoke(cli, [
                'db-query', 'SELECT * FROM markdown_files WHERE id = -1',
                '--format', 'yaml'
            ])
            assert result.exit_code == 0

            # Test table format with empty results
            result = self.runner.invoke(cli, [
                'db-query', 'SELECT * FROM markdown_files WHERE id = -1',
                '--format', 'table'
            ])
            assert result.exit_code == 0

    def test_db_query_invalid_format_handling(self):
        """
        Test that db-query handles invalid format specifications gracefully.

        Clean implementation using new db-query command only.
        """
        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 TestDbSchemaOutputFormatting:
    """Test suite for db-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_db_schema_table_format(self):
        """
        Test that db-schema command produces readable table format.

        Clean implementation using new db-schema command only.
        """
        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_db_schema_json_format(self):
        """
        Test that db-schema command produces valid JSON format.

        Clean implementation using new db-schema command only.
        """
        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', 'json'])

            assert result.exit_code == 0
            try:
                parsed = json.loads(result.output.strip())
                assert 'markdown_files' in parsed
                assert 'columns' in parsed['markdown_files']
            except json.JSONDecodeError:
                pytest.fail(f"Schema JSON output should be valid JSON. Got: {repr(result.output)}")

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

        Clean implementation using new db-schema command only.
        """
        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(f"Schema YAML output should be valid YAML. Got: {repr(result.output)}")


class TestDbCommandsFormatConsistency:
    """Test suite for format consistency across db- commands."""

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

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

        Clean implementation using new db- commands only.
        """
        commands = [
            ['db-query', 'SELECT COUNT(*) FROM markdown_files'],
            ['db-schema']
        ]

        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_db_commands(self):
        """
        Test that format errors are handled consistently across db- commands.

        Clean implementation using new db- commands only.
        """
        commands = [
            ['db-query', 'SELECT COUNT(*) FROM markdown_files'],
            ['db-schema']
        ]

        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 TestDbCommandsAdvanced:
    """Test suite for advanced db- command functionality."""

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

    def test_db_query_sql_safety_constraints(self):
        """
        Test that db-query enforces SQL safety constraints.

        Clean implementation using new db-query command only.
        """
        dangerous_queries = [
            'DROP TABLE markdown_files',
            'DELETE FROM markdown_files',
            'UPDATE markdown_files SET content = NULL',
            'INSERT INTO markdown_files VALUES (1, "test.md")'
        ]

        for query in dangerous_queries:
            result = self.runner.invoke(cli, ['db-query', query])

            # Should either fail with exit code != 0 or show safety message
            assert (result.exit_code != 0 or
                    'not allowed' in result.output.lower() or
                    'forbidden' in result.output.lower() or
                    'denied' in result.output.lower() or
                    'read-only' in result.output.lower())

    def test_db_commands_help_functionality(self):
        """
        Test that db- commands provide helpful usage information.

        Clean implementation using new db- commands only.
        """
        commands = ['db-query', 'db-schema', 'db-delete', 'db-stats']

        for command in commands:
            result = self.runner.invoke(cli, [command, '--help'])
            assert result.exit_code == 0
            assert command in result.output.lower()
            assert 'usage' in result.output.lower() or 'help' in result.output.lower()


