"""
Tests for Issue #54: Add content field instruction capabilities

This test module implements comprehensive tests for content field instructions
that provide guidance for content authors during document generation.

Following TDD8 methodology - these tests are written before implementation.
"""

import json
import pytest
from pathlib import Path
from tempfile import NamedTemporaryFile
from click.testing import CliRunner

from markitect.cli import cli
from markitect.schema_generator import SchemaGenerator
from markitect.stub_generator import StubGenerator
from markitect.exceptions import InvalidInstructionTypeError


class TestIssue54ContentInstructions:
    """Test suite for content field instruction functionality."""

    def setup_method(self):
        """Set up test fixtures."""
        self.schema_generator = SchemaGenerator()
        self.stub_generator = StubGenerator()
        self.runner = CliRunner()

    def test_cli_accepts_include_content_instructions_option(self):
        """Test that CLI accepts --include-content-instructions option."""
        # Arrange
        markdown_content = """# Architecture Document

## Introduction
This section provides an overview of the system.

## Design Principles
Core principles guiding the design.
"""

        with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
            f.write(markdown_content)
            temp_file = Path(f.name)

        try:
            # Act
            result = self.runner.invoke(cli, [
                'schema-generate',
                '--include-content-instructions',
                str(temp_file)
            ])

            # Assert
            assert result.exit_code == 0, f"CLI should accept --include-content-instructions option, got: {result.output}"

        finally:
            temp_file.unlink()

    def test_schema_generation_with_content_instructions_includes_instruction_fields(self):
        """Test that schema generation with content instructions includes instruction fields."""
        # Arrange
        markdown_content = """# Software Architecture Document

## Introduction
This section provides an overview of the system architecture.

### Purpose
Explain the purpose and goals of this document.

## System Design
Describe the overall system design and architecture.
"""

        with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
            f.write(markdown_content)
            temp_file = Path(f.name)

        try:
            # Act
            schema = self.schema_generator.generate_schema_from_file(
                temp_file,
                include_content_instructions=True
            )

            # Assert - Schema should contain content instruction fields
            assert "properties" in schema
            assert "headings" in schema["properties"]

            headings = schema["properties"]["headings"]["properties"]

            # Level 1 heading should have content instructions
            level_1 = headings["level_1"]
            items_props = level_1["items"]["properties"]
            assert "x-markitect-content-instructions" in items_props
            assert items_props["x-markitect-content-instructions"]["type"] == "string"

            # Level 2 headings should have content instructions
            level_2 = headings["level_2"]
            items_props = level_2["items"]["properties"]
            assert "x-markitect-content-instructions" in items_props

        finally:
            temp_file.unlink()

    def test_schema_includes_content_instruction_metaschema_extension(self):
        """Test that schemas with content instructions include metaschema extension."""
        # Arrange
        markdown_content = """# Test Document

## Section A
Content for section A.
"""

        with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
            f.write(markdown_content)
            temp_file = Path(f.name)

        try:
            # Act
            schema = self.schema_generator.generate_schema_from_file(
                temp_file,
                include_content_instructions=True
            )

            # Assert - Should have metaschema extension
            assert "x-markitect-content-instructions-enabled" in schema
            assert schema["x-markitect-content-instructions-enabled"] is True

        finally:
            temp_file.unlink()

    def test_content_instructions_support_different_instruction_types(self):
        """Test that content instructions can specify different instruction types."""
        # Arrange
        markdown_content = """# Requirements Document

## Functional Requirements
List all functional requirements.

## Non-Functional Requirements
Describe performance, security, and usability requirements.
"""

        with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
            f.write(markdown_content)
            temp_file = Path(f.name)

        try:
            # Act
            schema = self.schema_generator.generate_schema_from_file(
                temp_file,
                include_content_instructions=True,
                instruction_type="description"
            )

            # Assert - Should have instruction type specified
            headings = schema["properties"]["headings"]["properties"]
            level_2 = headings["level_2"]
            items_props = level_2["items"]["properties"]

            assert "x-markitect-instruction-type" in items_props
            assert items_props["x-markitect-instruction-type"]["enum"] == ["description"]

        finally:
            temp_file.unlink()

    def test_content_instructions_integration_with_outline_mode(self):
        """Test that content instructions work with outline mode."""
        # Arrange
        markdown_content = """# Project Plan

## Phase 1: Planning
Planning activities and deliverables.

### Requirements Gathering
Gather and document all requirements.

### Architecture Design
Design the system architecture.

## Phase 2: Implementation
Implementation activities.
"""

        with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
            f.write(markdown_content)
            temp_file = Path(f.name)

        try:
            # Act
            result = self.runner.invoke(cli, [
                'schema-generate',
                '--mode', 'outline',
                '--include-content-instructions',
                '--depth', '2',
                str(temp_file)
            ])

            # Assert
            assert result.exit_code == 0
            schema = json.loads(result.output)

            # Should have both outline mode and content instructions extensions
            assert schema.get("x-markitect-outline-mode") is True
            assert schema.get("x-markitect-content-instructions-enabled") is True

            # Should only include headings up to depth 2
            headings = schema["properties"]["headings"]["properties"]
            assert "level_1" in headings
            assert "level_2" in headings
            assert "level_3" not in headings

            # Should have content instructions in the headings
            level_2 = headings["level_2"]
            items_props = level_2["items"]["properties"]
            assert "x-markitect-content-instructions" in items_props

        finally:
            temp_file.unlink()

    def test_content_instructions_for_paragraphs_and_lists(self):
        """Test that content instructions can be added for paragraphs and lists."""
        # Arrange
        markdown_content = """# User Guide

## Overview
This guide explains how to use the system.

Some introductory text here.

- Feature A
- Feature B
- Feature C

## Getting Started
Follow these steps to get started.
"""

        with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
            f.write(markdown_content)
            temp_file = Path(f.name)

        try:
            # Act
            schema = self.schema_generator.generate_schema_from_file(
                temp_file,
                include_content_instructions=True
            )

            # Assert - Paragraphs should have content instructions
            if "paragraphs" in schema["properties"]:
                paragraphs_schema = schema["properties"]["paragraphs"]
                items_props = paragraphs_schema["items"]["properties"]
                assert "x-markitect-content-instructions" in items_props

            # Lists should have content instructions
            if "lists" in schema["properties"]:
                lists_schema = schema["properties"]["lists"]
                items_props = lists_schema["items"]["properties"]
                assert "x-markitect-content-instructions" in items_props

        finally:
            temp_file.unlink()

    def test_stub_generation_includes_content_instruction_placeholders(self):
        """Test that stub generation includes content instruction placeholders."""
        # Arrange
        schema = {
            "$schema": "http://json-schema.org/draft-07/schema#",
            "type": "object",
            "title": "Test Schema",
            "x-markitect-content-instructions-enabled": True,
            "properties": {
                "headings": {
                    "type": "object",
                    "properties": {
                        "level_1": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {
                                    "content": {"type": "string"},
                                    "x-markitect-content-instructions": {
                                        "type": "string",
                                        "const": "Provide the main title of the document"
                                    }
                                }
                            }
                        },
                        "level_2": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {
                                    "content": {"type": "string"},
                                    "x-markitect-content-instructions": {
                                        "type": "string",
                                        "const": "Describe each major section of the document"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        # Act
        stub_content = self.stub_generator.generate_stub_from_schema(schema)

        # Assert - Stub should include instruction placeholders
        assert "Provide the main title of the document" in stub_content
        assert "Describe each major section of the document" in stub_content

    def test_cli_supports_instruction_type_parameter(self):
        """Test that CLI supports --instruction-type parameter."""
        # Arrange
        markdown_content = """# API Documentation

## Authentication
How to authenticate with the API.

## Endpoints
Available API endpoints.
"""

        with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
            f.write(markdown_content)
            temp_file = Path(f.name)

        try:
            # Act
            result = self.runner.invoke(cli, [
                'schema-generate',
                '--include-content-instructions',
                '--instruction-type', 'example',
                str(temp_file)
            ])

            # Assert
            assert result.exit_code == 0
            schema = json.loads(result.output)

            # Check that instruction type is set correctly
            headings = schema["properties"]["headings"]["properties"]
            level_1 = headings["level_1"]
            items_props = level_1["items"]["properties"]
            assert items_props["x-markitect-instruction-type"]["enum"] == ["example"]

        finally:
            temp_file.unlink()

    def test_backward_compatibility_without_content_instructions(self):
        """Test that existing behavior is maintained when content instructions are not enabled."""
        # Arrange
        markdown_content = """# Test Document

## Section One
Content here.
"""

        with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
            f.write(markdown_content)
            temp_file = Path(f.name)

        try:
            # Act - Generate schema without content instructions (default behavior)
            schema = self.schema_generator.generate_schema_from_file(temp_file)

            # Assert - Should NOT have content instruction fields
            headings = schema["properties"]["headings"]["properties"]
            level_1 = headings["level_1"]
            items_props = level_1["items"]["properties"]

            # Should not have content instruction fields
            assert "x-markitect-content-instructions" not in items_props
            assert "x-markitect-instruction-type" not in items_props

            # Should NOT have content instructions extension
            assert "x-markitect-content-instructions-enabled" not in schema

        finally:
            temp_file.unlink()

    def test_content_instructions_with_heading_text_capture_integration(self):
        """Test that content instructions work with heading text capture."""
        # Arrange
        markdown_content = """# Architecture Overview

## System Components
Core system components and their responsibilities.

## Data Flow
How data flows through the system.
"""

        with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
            f.write(markdown_content)
            temp_file = Path(f.name)

        try:
            # Act
            schema = self.schema_generator.generate_schema_from_file(
                temp_file,
                capture_heading_text=True,
                include_content_instructions=True
            )

            # Assert - Should have both heading text capture and content instructions
            assert schema.get("x-markitect-heading-text-capture") is True
            assert schema.get("x-markitect-content-instructions-enabled") is True

            # Headings should have both enum constraints and content instructions
            headings = schema["properties"]["headings"]["properties"]
            level_1 = headings["level_1"]
            items_props = level_1["items"]["properties"]

            # Should have enum constraint from heading text capture
            assert "enum" in items_props["content"]
            assert items_props["content"]["enum"] == ["Architecture Overview"]

            # Should also have content instructions
            assert "x-markitect-content-instructions" in items_props

        finally:
            temp_file.unlink()

    def test_cli_help_includes_content_instructions_options(self):
        """Test that CLI help includes documentation for content instruction options."""
        # Act
        result = self.runner.invoke(cli, ['schema-generate', '--help'])

        # Assert
        assert result.exit_code == 0
        help_text = result.output
        assert "--include-content-instructions" in help_text
        assert "--instruction-type" in help_text
        assert "content instructions" in help_text or "content guidance" in help_text

    def test_instruction_type_validation(self):
        """Test that --instruction-type parameter validates input correctly."""
        # Arrange
        markdown_content = """# Test Document

## Section
Content here.
"""

        with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
            f.write(markdown_content)
            temp_file = Path(f.name)

        try:
            # Act - Test invalid instruction type
            result = self.runner.invoke(cli, [
                'schema-generate',
                '--include-content-instructions',
                '--instruction-type', 'invalid-type',
                str(temp_file)
            ])

            # Assert
            assert result.exit_code != 0
            assert "Invalid instruction type" in result.output or "invalid-type" in result.output

        finally:
            temp_file.unlink()

    def test_content_instructions_generate_appropriate_default_text(self):
        """Test that content instructions generate appropriate default guidance text."""
        # Arrange
        markdown_content = """# Development Guide

## Prerequisites
System requirements and prerequisites.

### Software Requirements
Required software and versions.

## Installation
Step-by-step installation instructions.

## Configuration
How to configure the system.
"""

        with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
            f.write(markdown_content)
            temp_file = Path(f.name)

        try:
            # Act
            schema = self.schema_generator.generate_schema_from_file(
                temp_file,
                include_content_instructions=True,
                instruction_type="description"
            )

            # Assert - Content instructions should contain appropriate guidance
            headings = schema["properties"]["headings"]["properties"]

            # Level 1 should have appropriate instructions
            level_1 = headings["level_1"]
            items_props = level_1["items"]["properties"]
            instructions = items_props["x-markitect-content-instructions"]["const"]
            assert len(instructions) > 0
            assert isinstance(instructions, str)

            # Instructions should be contextually appropriate
            # (implementation will determine specific text)

        finally:
            temp_file.unlink()