"""
SpecGenerator - Document generator.
"""

import json
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from ..analyzer import ProjectAnalyzer

from ..utils import extract_intent_context, format_project_name
from .base import BaseGenerator


class SpecGenerator(BaseGenerator):
    """Generator for spec.md files."""

    def __init__(self, analyzer: "ProjectAnalyzer", format_type: str = "markdown"):
        """
        Initialize the spec generator.

        Args:
            analyzer: ProjectAnalyzer instance
            format_type: Output format ('markdown' or 'json')
        """
        super().__init__(analyzer)
        self.format_type = format_type

    def generate(self, description: str) -> str:
        """
        Generate specification document.

        Args:
            description: Project description for context

        Returns:
            Generated spec content
        """
        if self.format_type == "json":
            return self._generate_json()
        else:
            return self._generate_markdown(description)

    def _generate_json(self) -> str:
        """Generate JSON format specification."""
        data = {
            "metadata": {
                "generated": self.date,
                "feature_branch": "main",
                "status": "Active Development",
            },
            "statistics": {
                "endpoints": self.analyzer.endpoint_count,
                "models": self.analyzer.model_count,
                "views": self.analyzer.view_count,
                "services": self.analyzer.service_count,
                "features": self.analyzer.feature_count,
            },
            "endpoints": [
                {
                    "method": ep.method,
                    "path": ep.path,
                    "controller": ep.controller,
                    "authenticated": ep.authenticated,
                }
                for ep in self.analyzer.endpoints
            ],
            "models": [{"name": m.name, "fields": m.fields} for m in self.analyzer.models],
            "views": [{"name": v.name, "file": v.file_name} for v in self.analyzer.views],
            "services": [s.name for s in self.analyzer.services],
        }
        return json.dumps(data, indent=2)

    def _generate_markdown(self, description: str) -> str:
        """Generate Markdown format specification."""
        project_info = self.analyzer.get_project_info()
        display_name = format_project_name(project_info["name"])

        # Extract intent context from description
        intent_context = extract_intent_context(description)

        output = [
            f"# Feature Specification: {display_name}",
            "",
            "**Feature Branch**: `main`",
            f"**Created**: {self.date}",
            "**Status**: Active Development",
            "**Input**: Reverse-engineered from existing codebase",
            "",
            "## Project Overview",
            "",
            project_info["description"],
            "",
            "This specification was automatically generated by reverse-engineering the existing codebase.",
            "It documents the current implementation's capabilities, requirements, and architecture.",
            "",
            "**Note**: This is a living document generated from code analysis. User stories and requirements",
            "below represent the implemented functionality as detected from controllers, models, and services.",
            "",
            "## User Scenarios & Testing *(mandatory)*",
            "",
            f"**Application Purpose**: {description}",
            "",
        ]

        # Generate user stories
        story_num = 1
        controllers_seen = set()

        for endpoint in self.analyzer.endpoints[:6]:  # Limit to first 6 controllers
            if endpoint.controller in controllers_seen:
                continue
            controllers_seen.add(endpoint.controller)

            # Generate story for this controller
            actor, goal, benefit = self._infer_business_outcome(endpoint.controller, intent_context)

            feature_name = endpoint.controller.replace("Controller", "").replace("Api", "")
            priority = "P1" if story_num <= 3 else "P2"

            output.extend(
                [
                    "",
                    f"### User Story {story_num} - {feature_name} (Priority: {priority})",
                    "",
                    f"As a **{actor}**, I want to **{goal}**",
                    f"so that **I can {benefit}**.",
                    "",
                    "**Why this priority**: Core business value - this capability directly supports the application's primary purpose.",
                    "",
                    "**Independent Test**: Can be tested by exercising the available endpoints and verifying that users can achieve the stated goal.",
                    "",
                    "**Acceptance Scenarios**:",
                    "",
                    "1. **Given** I have valid data, **When** I make requests, **Then** I receive accurate results",
                    "2. **Given** I provide invalid data, **When** I attempt operations, **Then** I receive clear error messages",
                    "",
                    "---",
                ]
            )
            story_num += 1

        # Add UI story if views exist
        if self.analyzer.view_count > 0:
            output.extend(
                [
                    "",
                    f"### User Story {story_num} - User Interface Interactions (Priority: P1)",
                    "",
                    "As a **system user**, I want to **interact with a web-based interface**",
                    "so that **I can perform operations without needing to use API calls directly**.",
                    "",
                    f"**Why this priority**: The UI provides the primary user experience with {self.analyzer.view_count} views available.",
                    "",
                    "**Independent Test**: Can be fully tested by navigating through available views and verifying all interactive elements function correctly.",
                    "",
                    "**Acceptance Scenarios**:",
                    "",
                    "1. **Given** I access the application, **When** I navigate between views, **Then** the interface responds smoothly",
                    "2. **Given** I interact with forms, **When** I submit data, **Then** it is processed correctly",
                    "3. **Given** I view data displays, **When** information is loaded, **Then** it is presented clearly and accurately",
                    "4. **Given** errors occur, **When** I receive feedback, **Then** messages are helpful and actionable",
                    "",
                    "---",
                ]
            )

        # Add edge cases and requirements
        output.extend(
            [
                "",
                "### Edge Cases",
                "",
                "- What happens when **invalid data is submitted** to API endpoints?",
                "- How does the system handle **concurrent modifications** to the same entity?",
                "- What occurs when **required authentication** is missing or expired?",
                "- How does the system respond to **malformed JSON** in requests?",
                "- What happens when **database connections fail** during operations?",
                "",
                "## Requirements *(mandatory)*",
                "",
                "### Functional Requirements",
                "",
            ]
        )

        # Generate functional requirements
        req_counter = 1

        # Check for authentication
        if any(ep.authenticated for ep in self.analyzer.endpoints):
            output.append(
                f"- **FR-{req_counter:03d}**: System MUST provide authentication and authorization for protected endpoints"
            )
            req_counter += 1

        # Check for HTTP methods
        methods = set(ep.method for ep in self.analyzer.endpoints)
        if "GET" in methods:
            output.append(
                f"- **FR-{req_counter:03d}**: System MUST support retrieval of data via GET endpoints"
            )
            req_counter += 1
        if "POST" in methods:
            output.append(
                f"- **FR-{req_counter:03d}**: System MUST support creation of new entities via POST endpoints"
            )
            req_counter += 1
        if "PUT" in methods or "PATCH" in methods:
            output.append(
                f"- **FR-{req_counter:03d}**: System MUST support updates to existing entities via PUT/PATCH endpoints"
            )
            req_counter += 1
        if "DELETE" in methods:
            output.append(
                f"- **FR-{req_counter:03d}**: System MUST support deletion of entities via DELETE endpoints"
            )
            req_counter += 1

        output.extend(
            [
                f"- **FR-{req_counter:03d}**: System MUST validate all input data for correctness and completeness",
            ]
        )
        req_counter += 1
        output.extend(
            [
                f"- **FR-{req_counter:03d}**: System MUST return appropriate HTTP status codes for all operations",
            ]
        )
        req_counter += 1
        output.extend(
            [
                f"- **FR-{req_counter:03d}**: System MUST handle errors gracefully with meaningful error messages",
            ]
        )
        req_counter += 1

        if self.analyzer.model_count > 0:
            output.append(
                f"- **FR-{req_counter:03d}**: System MUST persist data using {self.analyzer.model_count} defined data models"
            )

        # Key entities
        output.extend(
            [
                "",
                "### Key Entities",
                "",
                f"**Discovered Models** ({self.analyzer.model_count} total):",
                "",
            ]
        )

        for model in self.analyzer.models:
            output.append(f"- **{model.name}**: {model.fields} fields")

        # Success criteria
        output.extend(
            [
                "",
                "## Success Criteria *(mandatory)*",
                "",
                "### Measurable Outcomes",
                "",
                "- **SC-001**: API endpoints respond within acceptable time limits (< 2 seconds for 95% of requests)",
                "- **SC-002**: System successfully handles concurrent requests without data corruption",
                "- **SC-003**: All CRUD operations complete successfully with proper validation",
                "- **SC-004**: Error responses include meaningful messages and appropriate HTTP status codes",
                "- **SC-005**: Data persistence maintains integrity across all operations",
                "- **SC-006**: Authentication and authorization function correctly for protected resources",
                f"- **SC-007**: System scales to handle expected user load ({self.analyzer.endpoint_count} endpoints, {self.analyzer.model_count} models)",
                "- **SC-008**: All functional requirements are testable and verified",
                "",
                "## Technical Implementation Details",
                "",
                "### API Endpoints Discovered",
                "",
                f"Total endpoints: {self.analyzer.endpoint_count}",
                "",
            ]
        )

        # Group endpoints by controller
        current_controller = ""
        for endpoint in self.analyzer.endpoints:
            if endpoint.controller != current_controller:
                if current_controller:
                    output.append("")
                output.append(f"**{endpoint.controller} Controller**:")
                output.append("")
                current_controller = endpoint.controller

            output.append(f"- `{endpoint.method} {endpoint.path}` {endpoint}")

        # UI Views
        output.extend(
            [
                "",
                "### UI Views Discovered",
                "",
                f"Total views: {self.analyzer.view_count}",
                "",
            ]
        )

        for view in self.analyzer.views:
            output.append(f"- **{view.name}**: `{view.file_name}`")

        # Backend services
        output.extend(
            [
                "",
                "### Backend Services Discovered",
                "",
                f"Total services: {self.analyzer.service_count}",
                "",
            ]
        )

        for service in self.analyzer.services:
            output.append(f"- {service.name}")

        # Technology stack
        output.extend(
            [
                "",
                "### Technology Stack",
                "",
            ]
        )

        if project_info["language"] != "NEEDS CLARIFICATION":
            output.append(f"- **Language/Runtime**: {project_info['language']}")

        if project_info["dependencies"] != "NEEDS CLARIFICATION":
            formatted_deps = project_info["dependencies"].replace(", ", " + ")
            output.append(f"- **Frameworks**: {formatted_deps}")

        if project_info["storage"] != "N/A":
            formatted_storage = project_info["storage"].replace(", ", " + ")
            output.append(f"- **Data Storage**: {formatted_storage}")

        if project_info["testing"] != "NEEDS CLARIFICATION":
            formatted_testing = project_info["testing"].replace(", ", " + ")
            output.append(f"- **Testing**: {formatted_testing}")

        # Check for build tools
        if list(self.analyzer.repo_root.rglob("pom.xml")):
            output.append("- **Build Tool**: Maven")
        elif list(self.analyzer.repo_root.rglob("build.gradle")):
            output.append("- **Build Tool**: Gradle")
        elif list(self.analyzer.repo_root.rglob("package.json")):
            output.append("- **Build Tool**: npm/yarn/pnpm")

        # Footer
        output.extend(
            [
                "",
                "---",
                "",
                f"**Generated**: {self.date} by reverse-engineer",
                f"**Analysis**: {self.analyzer.endpoint_count} endpoints, {self.analyzer.model_count} models, {self.analyzer.view_count} views, {self.analyzer.service_count} services",
            ]
        )

        return "\n".join(output)

    def _infer_business_outcome(self, controller: str, intent_context: dict) -> tuple:
        """Infer actor, goal, and benefit for a controller."""
        # Simple inference based on controller name
        controller_lower = controller.lower()

        # Infer actor
        if "auth" in controller_lower or "login" in controller_lower:
            actor = "system user"
        elif "admin" in controller_lower:
            actor = "administrator"
        else:
            actor = "user"

        # Infer goal and benefit
        entity = controller.replace("Controller", "").replace("Api", "")

        # Use intent verbs if available
        if intent_context.get("verbs"):
            verb = intent_context["verbs"][0]
            goal = f"{verb} {entity} data"
            benefit = f"support {verb} operations effectively"
        else:
            goal = f"manage {entity} data"
            benefit = f"maintain accurate {entity} information"

        return actor, goal, benefit
