"""
CLAUDE.md Linter — Validates the quality of a CLAUDE.md file.

Checks for:
- Token count (warn if > 1500)
- Missing required sections
- Dead file references
- Contradictory instructions
- Generic/unhelpful content
- Files referenced that don't exist
"""

import re
from pathlib import Path
from .token_counter import TokenCounter


# Sections that should be in every CLAUDE.md
RECOMMENDED_SECTIONS = {
    "project overview": ["overview", "about", "what is", "description"],
    "tech stack": ["stack", "technology", "dependencies", "built with", "requirements"],
    "architecture": ["architecture", "structure", "directory", "organization", "layout"],
    "conventions": ["conventions", "patterns", "style", "standards", "guidelines"],
    "commands": ["commands", "scripts", "how to run", "getting started", "quickstart", "setup"],
}

# Generic phrases that suggest unhelpful content
GENERIC_PHRASES = [
    "this is a",
    "feel free to",
    "don't hesitate to",
    "always remember to",
    "make sure to",
    "please note that",
    "it is important to",
    "note that this",
    "as mentioned above",
]


class ClaudeMdLinter:
    """Lints a CLAUDE.md file for quality issues."""

    def __init__(self, project_root: str = "."):
        self.root = Path(project_root)
        self.token_counter = TokenCounter()

    def lint(self, content: str) -> dict:
        """
        Run all lint checks on CLAUDE.md content.
        Returns list of issues with severity and suggestions.
        """
        issues = []

        issues.extend(self._check_token_count(content))
        issues.extend(self._check_required_sections(content))
        issues.extend(self._check_generic_content(content))
        issues.extend(self._check_formatting(content))
        issues.extend(self._check_dead_links(content))

        # Sort by severity
        severity_order = {"error": 0, "warning": 1, "info": 2}
        issues.sort(key=lambda x: severity_order.get(x["severity"], 3))

        return {
            "issues": issues,
            "errors": sum(1 for i in issues if i["severity"] == "error"),
            "warnings": sum(1 for i in issues if i["severity"] == "warning"),
            "info": sum(1 for i in issues if i["severity"] == "info"),
            "score": self._calculate_score(issues, content),
        }

    def lint_file(self, path: str = "CLAUDE.md") -> dict:
        """Lint a CLAUDE.md file at the given path."""
        full_path = self.root / path
        if not full_path.exists():
            return {
                "issues": [{"severity": "error", "message": f"File not found: {path}", "suggestion": "Run 'claudemd generate' to create it", "rule": "file_exists"}],
                "errors": 1,
                "warnings": 0,
                "info": 0,
                "score": 0,
            }
        content = full_path.read_text(encoding="utf-8", errors="ignore")
        return self.lint(content)

    def _check_token_count(self, content: str) -> list[dict]:
        """Check if the file is too long."""
        issues = []
        token_data = self.token_counter.analyze(content)
        total = token_data["total"]

        if total > 3000:
            issues.append({
                "severity": "error",
                "message": f"CLAUDE.md is {total} tokens — this is very long and wastes context",
                "suggestion": "Reduce to under 1500 tokens. Remove generic info the AI can infer from reading code.",
                "rule": "token_count",
                "tokens": total,
            })
        elif total > 1500:
            issues.append({
                "severity": "warning",
                "message": f"CLAUDE.md is {total} tokens — recommended max is 1500",
                "suggestion": "Consider trimming verbose sections. Top token users: " +
                              ", ".join(f"{k} ({v})" for k, v in list(token_data.get("by_section", {}).items())[:3]),
                "rule": "token_count",
                "tokens": total,
            })

        if total < 100:
            issues.append({
                "severity": "warning",
                "message": f"CLAUDE.md is only {total} tokens — this is very short",
                "suggestion": "Add more context: architecture, conventions, and key commands",
                "rule": "token_count_minimum",
                "tokens": total,
            })

        return issues

    def _check_required_sections(self, content: str) -> list[dict]:
        """Check if required sections are present."""
        issues = []
        content_lower = content.lower()

        for section_type, keywords in RECOMMENDED_SECTIONS.items():
            found = any(kw in content_lower for kw in keywords)
            if not found:
                issues.append({
                    "severity": "info",
                    "message": f"Missing section: {section_type}",
                    "suggestion": f"Add a section covering {section_type}. Useful keywords: {', '.join(keywords[:3])}",
                    "rule": "required_section",
                    "section": section_type,
                })

        return issues

    def _check_generic_content(self, content: str) -> list[dict]:
        """Check for generic, unhelpful phrases."""
        issues = []
        content_lower = content.lower()

        generic_found = [p for p in GENERIC_PHRASES if p in content_lower]
        if len(generic_found) >= 3:
            issues.append({
                "severity": "info",
                "message": f"Contains {len(generic_found)} generic phrases that aren't specific to this project",
                "suggestion": f"Replace generic phrases like: {', '.join(f'\"{p}\"' for p in generic_found[:3])} with specific project details",
                "rule": "generic_content",
            })

        # Check for placeholder text
        placeholders = re.findall(r"\[.*?\]", content)
        unfilled = [p for p in placeholders if any(word in p.lower() for word in ["todo", "fill", "your", "add here", "placeholder"])]
        if unfilled:
            issues.append({
                "severity": "warning",
                "message": f"Contains {len(unfilled)} unfilled placeholder(s): {', '.join(unfilled[:3])}",
                "suggestion": "Fill in or remove placeholder sections",
                "rule": "placeholders",
            })

        return issues

    def _check_formatting(self, content: str) -> list[dict]:
        """Check formatting quality."""
        issues = []

        # Check for headers
        headers = re.findall(r"^#+\s+.+", content, re.MULTILINE)
        if not headers:
            issues.append({
                "severity": "warning",
                "message": "No markdown headers found",
                "suggestion": "Use ## headers to organize sections. AI assistants use headers to navigate to relevant context.",
                "rule": "no_headers",
            })
        elif len(headers) < 3:
            issues.append({
                "severity": "info",
                "message": f"Only {len(headers)} section header(s) — consider more organization",
                "suggestion": "Add sections for: tech stack, architecture, conventions, commands",
                "rule": "few_headers",
            })

        # Check line length (very long lines are hard to parse)
        long_lines = [i + 1 for i, line in enumerate(content.split("\n"))
                      if len(line) > 200 and not line.startswith("http")]
        if long_lines:
            issues.append({
                "severity": "info",
                "message": f"Lines {long_lines[:3]} are very long (>200 chars)",
                "suggestion": "Break long lines into bullet points for better AI parsing",
                "rule": "long_lines",
            })

        return issues

    def _check_dead_links(self, content: str) -> list[dict]:
        """Check for references to non-existent files."""
        issues = []

        # Find file references
        file_pattern = r"`([a-zA-Z0-9_./\\-]+\.[a-zA-Z]{2,5})`"
        refs = re.findall(file_pattern, content)

        dead = []
        for ref in refs:
            if "*" in ref or len(ref) < 4:
                continue
            if ref.startswith(("http", "www", "#")):
                continue
            full = self.root / ref
            if not full.exists():
                dead.append(ref)

        if dead:
            issues.append({
                "severity": "warning",
                "message": f"References to {len(dead)} file(s) that don't exist: {', '.join(dead[:4])}",
                "suggestion": "Update or remove references to deleted files",
                "rule": "dead_file_refs",
                "dead_files": dead,
            })

        return issues

    def _calculate_score(self, issues: list[dict], content: str) -> int:
        """Calculate quality score (0-100, higher is better)."""
        score = 100

        for issue in issues:
            if issue["severity"] == "error":
                score -= 25
            elif issue["severity"] == "warning":
                score -= 10
            else:
                score -= 3

        # Bonus for good token count
        tokens = self.token_counter.count(content)
        if 300 <= tokens <= 1200:
            score += 5  # Sweet spot

        return max(0, min(100, score))

    def format_report(self, result: dict = None, content: str = None, path: str = "CLAUDE.md") -> str:
        """Format a human-readable lint report."""
        if result is None:
            if content:
                result = self.lint(content)
            else:
                result = self.lint_file(path)

        score = result.get("score", 0)
        lines = [
            f"CLAUDE.md Quality Score: {score}/100",
            f"Issues: {result['errors']} errors, {result['warnings']} warnings, {result['info']} info",
        ]

        if not result["issues"]:
            lines.append("\n[OK] No issues found! Your CLAUDE.md looks great.")
        else:
            lines.append("\nIssues found:")
            for issue in result["issues"]:
                icon = "[ERROR]" if issue["severity"] == "error" else "[WARN]" if issue["severity"] == "warning" else "[INFO]"
                lines.append(f"\n  {icon} {issue['message']}")
                lines.append(f"     Fix: {issue['suggestion']}")

        return "\n".join(lines)
