"""Semi-dynamic parsers for CloudSense repository README files.

Extracts structured package metadata from:
- source-code/apex-packages/README.md  (Apex managed packages)
- source-code/ecs-services/README.md   (ECS cloud services)
- source-code/eks-services/README.md   (EKS cloud services)

The parsing uses fixed field patterns (not LLM interpretation) but reads
field VALUES at runtime.  If a field is missing or the format drifts,
the parser gracefully skips it rather than crashing.
"""

from __future__ import annotations

import logging
import re
from typing import Any

logger = logging.getLogger(__name__)

# ---------------------------------------------------------------------------
# Apex-packages README parser
# ---------------------------------------------------------------------------

_APEX_SECTION_RE = re.compile(
    r"^###\s+.*?\*\*(cloudsense-[\w-]+)\*\*\s+\[(\w+)\]",
    re.MULTILINE,
)

_FIELD_PATTERNS: dict[str, re.Pattern[str]] = {
    "repository": re.compile(
        r"-\s+\*\*Repository:\*\*\s*(https?://\S+)", re.IGNORECASE
    ),
    "package_name": re.compile(
        r"-\s+\*\*Package Name:\*\*\s*(.+)", re.IGNORECASE
    ),
    "latest_version": re.compile(
        r"-\s+\*\*Latest Version:\*\*\s*(.+)", re.IGNORECASE
    ),
    "total_versions": re.compile(
        r"-\s+\*\*Total Versions:\*\*\s*(\d+)", re.IGNORECASE
    ),
    "customer_usage": re.compile(
        r"-\s+\*\*Customer Usage:\*\*\s*(\d+)", re.IGNORECASE
    ),
    "r38_created": re.compile(
        r"-\s+\*\*R38 Package Created:\*\*\s*(.+)", re.IGNORECASE
    ),
    "branches": re.compile(
        r"-\s+\*\*Branches:\*\*\s*(.+)", re.IGNORECASE
    ),
    "status": re.compile(
        r"-\s+\*\*Status:\*\*\s*(.+)", re.IGNORECASE
    ),
    "migration_notes": re.compile(
        r"-\s+\*\*Migration Notes:\*\*\s*(.+)", re.IGNORECASE
    ),
    "chosen_baseline": re.compile(
        r"-\s+\*\*Chosen Baseline:\*\*\s*(.+)", re.IGNORECASE
    ),
    "special_notes": re.compile(
        r"-\s+\*\*Special Notes:\*\*\s*(.+)", re.IGNORECASE
    ),
}

_YES_TOKENS = {"yes", "✅ yes", "✅"}
_DEPRECATED_TOKENS = {"deprecated", "**deprecated**"}
_IDENTICAL_PHRASES = [
    "identical branches",
    "identical",
    "identicals",
    "are the same",
    "no changes",
    "no code changes",
    "no changes in r36-38",
    "no changes from r35",
    "no changes across releases",
    "there are no code changes across releases",
]


def _parse_branches(raw: str) -> list[str]:
    """'R38, R37, R36-MR1' -> ['R38', 'R37', 'R36-MR1']"""
    return [b.strip() for b in raw.split(",") if b.strip()]


def _parse_bool_marker(raw: str) -> bool:
    return raw.strip().lower() in _YES_TOKENS


def _is_deprecated(status_raw: str) -> bool:
    return status_raw.strip().lower().rstrip("*").lstrip("*") in _DEPRECATED_TOKENS


def _infer_identical_versions(migration_notes: str | None) -> bool:
    if not migration_notes:
        return False
    lower = migration_notes.lower()
    return any(phrase in lower for phrase in _IDENTICAL_PHRASES)


def _infer_migration_complexity(migration_notes: str | None) -> str:
    """Classify migration complexity from migration notes text."""
    if not migration_notes:
        return "unknown"
    lower = migration_notes.lower()
    if _infer_identical_versions(migration_notes):
        return "none"
    high_signals = [
        "major", "extensive", "significant", "high",
        "architectural", "breaking",
    ]
    low_signals = [
        "minor", "documentation", "doc", "documentation only",
        "documentation updates", "tech debt", "sf api version",
    ]
    if any(s in lower for s in high_signals):
        return "high"
    if any(s in lower for s in low_signals):
        return "low"
    return "medium"


def _parse_replacement(migration_notes: str | None) -> dict[str, Any] | None:
    """Try to extract replacement info from migration notes for deprecated packages."""
    if not migration_notes:
        return None
    lower = migration_notes.lower()
    patterns = [
        (r"merged into (\w+)", "merged"),
        (r"absorbed into (\w+)", "merged"),
        (r"replaced by (\w+)", "replaced"),
        (r"superseded by (\w+)", "replaced"),
        (r"renamed to (\w+)", "renamed"),
        (r"functionality (?:moved|migrated) to (\w+)", "merged"),
    ]
    for pattern, rtype in patterns:
        m = re.search(pattern, lower)
        if m:
            return {"replaced_by": m.group(1), "type": rtype}
    return None


def parse_apex_packages_readme(content: str) -> list[dict[str, Any]]:
    """Parse the apex-packages/README.md into structured per-package dicts.

    Returns a list of dicts, one per package section found in the README.
    Each dict has keys like: repo_name, namespace, repository, branches,
    status, deprecated, r38_created, customer_usage, chosen_baseline,
    migration_notes, migration_complexity, identical_versions, etc.
    """
    matches = list(_APEX_SECTION_RE.finditer(content))
    if not matches:
        logger.warning("No package sections found in apex-packages README")
        return []

    packages: list[dict[str, Any]] = []

    for i, match in enumerate(matches):
        start = match.start()
        end = matches[i + 1].start() if i + 1 < len(matches) else len(content)
        section = content[start:end]

        repo_name = match.group(1)
        namespace = match.group(2)

        entry: dict[str, Any] = {
            "repo_name": repo_name,
            "namespace": namespace,
        }

        for field_name, pattern in _FIELD_PATTERNS.items():
            m = pattern.search(section)
            if m:
                entry[field_name] = m.group(1).strip()

        if "branches" in entry:
            entry["branches"] = _parse_branches(entry["branches"])

        if "r38_created" in entry:
            entry["r38_created"] = _parse_bool_marker(entry["r38_created"])
        else:
            entry["r38_created"] = False

        if "customer_usage" in entry:
            try:
                entry["customer_usage"] = int(entry["customer_usage"])
            except (ValueError, TypeError):
                entry["customer_usage"] = 0
        else:
            entry["customer_usage"] = 0

        if "total_versions" in entry:
            try:
                entry["total_versions"] = int(entry["total_versions"])
            except (ValueError, TypeError):
                pass

        status_raw = entry.get("status", "")
        entry["deprecated"] = _is_deprecated(status_raw)
        entry["status"] = (
            "deprecated" if entry["deprecated"]
            else status_raw.strip().lower().replace("production package", "production")
        )

        migration_notes = entry.get("migration_notes")
        entry["identical_versions"] = _infer_identical_versions(migration_notes)
        entry["migration_complexity"] = _infer_migration_complexity(migration_notes)

        if entry["deprecated"]:
            replacement = _parse_replacement(migration_notes)
            if replacement:
                entry["replacement"] = replacement

        code_empty = False
        if "special_notes" in entry:
            if "no code" in entry["special_notes"].lower():
                code_empty = True
        entry["code_empty"] = code_empty

        url = entry.get("repository", "")
        if url:
            entry["url"] = url.rstrip("/")
        else:
            entry["url"] = f"https://github.com/trilogy-group/{repo_name}"

        packages.append(entry)

    logger.info(
        "Parsed %d packages from apex-packages README "
        "(%d deprecated, %d identical-version)",
        len(packages),
        sum(1 for p in packages if p.get("deprecated")),
        sum(1 for p in packages if p.get("identical_versions")),
    )

    return packages


# ---------------------------------------------------------------------------
# ECS / EKS service README parser
# ---------------------------------------------------------------------------

_CLOUD_SERVICE_SECTION_RE = re.compile(
    r"^###\s+\*\*.*?(cloudsense-[\w-]+)\*\*\s+\[([^\]]+)\]",
    re.MULTILINE,
)

_CS_FIELD_PATTERNS: dict[str, re.Pattern[str]] = {
    "repository": re.compile(
        r"-\s+\*\*Repository:\*\*\s*(https?://\S+)", re.IGNORECASE
    ),
    "service_name": re.compile(
        r"-\s+\*\*Service Name:\*\*\s*(.+)", re.IGNORECASE
    ),
    "status": re.compile(
        r"-\s+\*\*Status:\*\*\s*(.+)", re.IGNORECASE
    ),
    "dual_deployment": re.compile(
        r"-\s+\*\*Dual Deployment:\*\*\s*(.+)", re.IGNORECASE
    ),
    "special_notes": re.compile(
        r"-\s+\*\*Special Notes:\*\*\s*(.+)", re.IGNORECASE
    ),
}


def parse_cloud_services_readme(
    content: str,
    service_type: str = "ecs",
) -> list[dict[str, Any]]:
    """Parse an ECS or EKS services README into structured dicts.

    Returns a list of dicts with: repo_name, directory, repository,
    service_name, service_type, status.
    """
    matches = list(_CLOUD_SERVICE_SECTION_RE.finditer(content))
    if not matches:
        logger.warning("No service sections found in %s README", service_type)
        return []

    services: list[dict[str, Any]] = []

    for i, match in enumerate(matches):
        start = match.start()
        end = matches[i + 1].start() if i + 1 < len(matches) else len(content)
        section = content[start:end]

        repo_name = match.group(1)
        directory = match.group(2).rstrip("/")

        entry: dict[str, Any] = {
            "repo_name": repo_name,
            "directory": directory,
            "service_type": service_type,
        }

        for field_name, pattern in _CS_FIELD_PATTERNS.items():
            m = pattern.search(section)
            if m:
                entry[field_name] = m.group(1).strip()

        url = entry.get("repository", "")
        if url:
            entry["url"] = url.rstrip("/")
        else:
            entry["url"] = f"https://github.com/trilogy-group/{repo_name}"

        services.append(entry)

    logger.info("Parsed %d %s services from README", len(services), service_type)
    return services


# ---------------------------------------------------------------------------
# Apex <-> Cloud-service linking
# ---------------------------------------------------------------------------

_APEX_TO_CLOUD_KNOWN: dict[str, list[str]] = {
    "cspofa": ["cloudsense-orchestrator-poller-migrated"],
    "cscfga": ["cloudsense-configurator-node-service"],
    "cssmgnt": ["cloudsense-cs-solution-management-service"],
    "csord": ["cloudsense-orders-subscriptions-service"],
    "csam": ["cloudsense-messaging-dispatcher"],
    "csclmcb": ["cloudsense-clm-codebase"],
    "csb2c": [
        "cloudsense-ecommerce-api",
        "cloudsense-ecommerce-etl",
        "cloudsense-ecommerce-messaging-heroku",
    ],
    "csdf": [
        "cloudsense-media-fulfilment-java-fw",
        "cloudsense-digital-fulfilment-heroku",
    ],
    "csmm": ["cloudsense-mass-macd"],
}


def build_cloud_service_map(
    ecs_services: list[dict[str, Any]],
    eks_services: list[dict[str, Any]],
) -> dict[str, list[dict[str, str]]]:
    """Build a mapping of Apex namespace -> list of cloud service repos.

    Uses the known mapping above, enriched with actual repo URLs from
    the parsed ECS/EKS service lists.
    """
    all_services = {s["repo_name"]: s for s in ecs_services + eks_services}
    result: dict[str, list[dict[str, str]]] = {}

    for namespace, repo_names in _APEX_TO_CLOUD_KNOWN.items():
        entries = []
        for rn in repo_names:
            svc = all_services.get(rn, {})
            entries.append({
                "repo_name": rn,
                "url": svc.get("url", f"https://github.com/trilogy-group/{rn}"),
                "service_type": svc.get("service_type", "unknown"),
                "service_name": svc.get("service_name", rn),
            })
        result[namespace] = entries

    return result
