"""Entity extraction from memory content - regex-based NER."""

from __future__ import annotations

import re

from neurovault.models import EntityType


class EntityExtractor:
    """Extract named entities without ML models (regex + dictionary)."""

    TECH_DICT = {
        "python", "javascript", "typescript", "rust", "go", "java", "ruby", "swift",
        "react", "vue", "angular", "svelte", "next.js", "nuxt", "fastapi", "flask",
        "django", "express", "nest.js", "postgresql", "mysql", "sqlite", "mongodb",
        "redis", "kafka", "rabbitmq", "docker", "kubernetes", "terraform",
        "aws", "gcp", "azure", "vercel", "netlify", "cloudflare",
        "langchain", "pytorch", "tensorflow", "huggingface", "ollama",
        "git", "github", "gitlab", "bitbucket", "openai", "anthropic", "gemini",
        "claude", "gpt", "llama", "mistral", "chromadb", "pinecone", "qdrant",
    }

    DATE_PATTERNS = [
        r"\b(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\w*\.?\s+\d{1,2}(?:st|nd|rd|th)?,?\s*\d{0,4}\b",
        r"\b\d{4}-\d{2}-\d{2}\b",
        r"\b(?:today|tomorrow|yesterday)\b",
        r"\b(?:next|this|last)\s+(?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday)\b",
        r"\b(?:next|this|last)\s+(?:week|month|quarter|year)\b",
    ]

    METRIC_PATTERNS = [
        r"\b\d+(?:\.\d+)?%",
        r"\$\d+(?:,\d{3})*(?:\.\d{2})?\s*[KMBTkmbt]?",
        r"\b\d+(?:\.\d+)?\s*(?:ms|seconds?|minutes?|hours?|days?|GB|MB|KB|TB|QPS|RPS|FPS)",
    ]

    URL_PATTERN = r"https?://[^\s<>\"')]+|www\.[^\s<>\"')]+\.[a-z]{2,}"
    FILE_PATTERN = r"\b[\w/.-]+\.(?:py|js|ts|md|txt|json|yaml|toml|css|html|sql|sh|go|rs|java)\b"
    PERSON_STOPWORDS = {
        "the",
        "however",
        "but",
        "and",
        "or",
        "if",
        "then",
        "this",
        "that",
        "these",
        "those",
        "today",
        "tomorrow",
        "yesterday",
        "meeting",
        "project",
        "task",
        "note",
    }

    def extract(self, content: str) -> list[dict]:
        entities: list[dict] = []
        lower = content.lower()

        for tech in self.TECH_DICT:
            if tech in lower:
                entities.append({"name": tech, "type": EntityType.TECHNOLOGY, "confidence": 0.95})

        for pattern in self.DATE_PATTERNS:
            for match in re.finditer(pattern, content, re.IGNORECASE):
                entities.append({"name": match.group(), "type": EntityType.DATE, "confidence": 0.9})

        for pattern in self.METRIC_PATTERNS:
            for match in re.finditer(pattern, content):
                entities.append({"name": match.group(), "type": EntityType.METRIC, "confidence": 0.85})

        for match in re.finditer(self.URL_PATTERN, content):
            entities.append({"name": match.group(), "type": EntityType.URL, "confidence": 0.99})

        for match in re.finditer(self.FILE_PATTERN, content):
            entities.append({"name": match.group(), "type": EntityType.FILE, "confidence": 0.9})

        for match in re.finditer(r"\b([A-Z][a-z]+(?:\s+[A-Z][a-z]+){0,2})\b", content):
            name = match.group()
            lowered = name.lower()
            if lowered in self.TECH_DICT or lowered in self.PERSON_STOPWORDS or len(name) <= 2:
                continue
            word_count = len(name.split())
            entity_type = EntityType.PERSON if word_count <= 2 else EntityType.ORGANIZATION
            entities.append({"name": name, "type": entity_type, "confidence": 0.6})

        return self._deduplicate(entities)

    def _deduplicate(self, entities: list[dict]) -> list[dict]:
        seen = set()
        unique = []
        for entity in entities:
            key = (entity["name"].lower(), entity["type"])
            if key in seen:
                continue
            seen.add(key)
            unique.append(entity)
        return unique
