"""Tag inheritance engine for document/section/block cascading.

Implements inheritance logic per Spec Section 3.1.
"""

import re
from pathlib import Path
from typing import Any, Optional
from uuid import uuid4

import structlog

from src.api.schemas.tags import TagAssignment, TagHistoryEntry, TagSource, TagStatus

logger = structlog.get_logger(__name__)


class InheritanceEngine:
    """Manages tag inheritance from document → section → block.

    Phase 3 Enhancement: Implements hierarchical tag cascading per Spec Section 3.1.
    """

    def __init__(self):
        """Initialize inheritance engine."""
        self.logger = structlog.get_logger(__name__)

        # Keyword patterns for section-level tag inference
        self.section_patterns = {
            # Requirements
            "topic:requirements": r"(requirement|functional|non[\-\s]?functional|user\s+stor)",
            "topic:security": r"(security|auth|authorization|authentication|encryption|access\s+control)",
            "topic:performance": r"(performance|scalability|latency|throughput|response\s+time)",
            "topic:testing": r"(test|testing|qa|quality\s+assurance|validation|verification)",
            "topic:architecture": r"(architecture|design|system\s+design|component|module)",
            "topic:api": r"(api|endpoint|interface|rest|graphql)",
            "topic:database": r"(database|db|schema|table|query|migration)",
            "topic:deployment": r"(deployment|infrastructure|devops|ci[\-/]cd|pipeline)",
            "topic:documentation": r"(doc|documentation|manual|guide|tutorial)",
            "topic:compliance": r"(compliance|regulatory|gdpr|hipaa|pci|sox)",
        }

    def extract_document_tags(
        self,
        filename: Optional[str] = None,
        metadata: Optional[dict[str, Any]] = None,
    ) -> list[TagAssignment]:
        """Extract document-level tags from filename and metadata.

        Args:
            filename: Document filename (e.g., "requirements.xlsx")
            metadata: Document metadata dict

        Returns:
            List of TagAssignment objects with source='inheritance_doc'
        """
        doc_tags = []
        current_ts = int(__import__("time").time())

        # Extract from filename
        if filename:
            filename_lower = Path(filename).stem.lower()

            # Document type inference
            doc_type_patterns = {
                "doc:reference": r"(spec|specification|reference|api)",
                "doc:guide": r"(guide|manual|howto|how[\-\s]to)",
                "doc:tutorial": r"(tutorial|getting[\-\s]started|quickstart)",
                "req:functional": r"(requirement|functional|user[\-\s]story|feature)",
                "test:plan": r"(test[\-\s]plan|testing|qa)",
                "arch:decision": r"(adr|architecture[\-\s]decision|design[\-\s]doc)",
            }

            for tag_name, pattern in doc_type_patterns.items():
                if re.search(pattern, filename_lower):
                    doc_tags.append(
                        TagAssignment(
                            tag_id=str(uuid4()),
                            name=tag_name,
                            source=TagSource.INHERITANCE_DOC,
                            confidence=0.9,  # High confidence from filename
                            status=TagStatus.VERIFIED,
                            history=[
                                TagHistoryEntry(
                                    action="suggested",
                                    by="inheritance_engine",
                                    ts=current_ts,
                                )
                            ],
                        )
                    )

        # Extract from metadata (if provided)
        if metadata:
            # Project metadata
            if "project" in metadata:
                project = metadata["project"]
                doc_tags.append(
                    TagAssignment(
                        tag_id=str(uuid4()),
                        name=f"entity:{project.lower().replace(' ', '_')}",
                        source=TagSource.INHERITANCE_DOC,
                        confidence=1.0,
                        status=TagStatus.VERIFIED,
                        history=[
                            TagHistoryEntry(
                                action="suggested",
                                by="inheritance_engine",
                                ts=current_ts,
                            )
                        ],
                    )
                )

            # Domain/Industry
            if "domain" in metadata:
                domain = metadata["domain"]
                doc_tags.append(
                    TagAssignment(
                        tag_id=str(uuid4()),
                        name=f"domain:{domain.lower().replace(' ', '_')}",
                        source=TagSource.INHERITANCE_DOC,
                        confidence=1.0,
                        status=TagStatus.VERIFIED,
                        history=[
                            TagHistoryEntry(
                                action="suggested",
                                by="inheritance_engine",
                                ts=current_ts,
                            )
                        ],
                    )
                )

        self.logger.info(
            "document_tags_extracted",
            filename=filename,
            tag_count=len(doc_tags),
        )

        return doc_tags

    def extract_section_tags(
        self, parent_header: Optional[str] = None, sheet_name: Optional[str] = None
    ) -> list[TagAssignment]:
        """Extract section-level tags from header/sheet name using keyword matching.

        Args:
            parent_header: Parent section header text
            sheet_name: Sheet or section name

        Returns:
            List of TagAssignment objects with source='inheritance_header'
        """
        section_tags = []
        current_ts = int(__import__("time").time())

        # Combine header and sheet name for pattern matching
        text_to_analyze = " ".join(
            filter(None, [parent_header or "", sheet_name or ""])
        ).lower()

        if not text_to_analyze.strip():
            return section_tags

        # Match against section patterns
        for tag_name, pattern in self.section_patterns.items():
            if re.search(pattern, text_to_analyze, re.IGNORECASE):
                section_tags.append(
                    TagAssignment(
                        tag_id=str(uuid4()),
                        name=tag_name,
                        source=TagSource.INHERITANCE_HEADER,
                        confidence=0.8,  # Moderate confidence from header
                        status=TagStatus.VERIFIED,
                        history=[
                            TagHistoryEntry(
                                action="suggested",
                                by="inheritance_engine",
                                ts=current_ts,
                            )
                        ],
                    )
                )

        self.logger.debug(
            "section_tags_extracted",
            parent_header=parent_header,
            sheet_name=sheet_name,
            tag_count=len(section_tags),
        )

        return section_tags

    def merge_tags(
        self,
        document_tags: list[TagAssignment],
        section_tags: list[TagAssignment],
        block_tags: list[TagAssignment],
    ) -> list[TagAssignment]:
        """Merge tags from all levels with deduplication.

        Args:
            document_tags: Document-level tags
            section_tags: Section-level tags
            block_tags: Block-level tags (from LLM)

        Returns:
            Merged list of TagAssignment objects (flattened)
        """
        # Use dict to deduplicate by tag name (keep highest confidence)
        merged = {}

        for tag_list in [document_tags, section_tags, block_tags]:
            for tag in tag_list:
                if tag.name not in merged:
                    merged[tag.name] = tag
                else:
                    # Keep tag with higher confidence
                    if tag.confidence > merged[tag.name].confidence:
                        merged[tag.name] = tag

        result = list(merged.values())

        self.logger.debug(
            "tags_merged",
            doc_count=len(document_tags),
            section_count=len(section_tags),
            block_count=len(block_tags),
            merged_count=len(result),
        )

        return result

    def apply_inheritance(
        self,
        records: list[dict[str, Any]],
        filename: Optional[str] = None,
        metadata: Optional[dict[str, Any]] = None,
    ) -> list[dict[str, Any]]:
        """Apply tag inheritance to all records.

        Args:
            records: List of record dicts with 'tags' field (block-level tags)
            filename: Document filename
            metadata: Document metadata

        Returns:
            Same records with tags merged from document/section/block levels
        """
        # Extract document-level tags once
        document_tags = self.extract_document_tags(filename, metadata)

        for record in records:
            # Extract section-level tags per record
            section_tags = self.extract_section_tags(
                parent_header=record.get("parent_header"),
                sheet_name=record.get("sheet_name"),
            )

            # Get block-level tags (should be TagAssignment objects)
            block_tags = record.get("tags", [])

            # Merge all levels
            merged_tags = self.merge_tags(document_tags, section_tags, block_tags)

            # Update record
            record["tags"] = merged_tags

        self.logger.info(
            "inheritance_applied",
            record_count=len(records),
            document_tags=len(document_tags),
        )

        return records
