"""Core rule engine — runs scanners and collects normalized findings."""

from __future__ import annotations

import logging
import time
from dataclasses import dataclass, field
from pathlib import Path
from typing import List, Optional

from ..scanners.detector import Platform, DetectionResult
from .config import ScanConfig

logger = logging.getLogger("oncecheck")


@dataclass
class Finding:
    """A single compliance finding produced by a scanner."""
    rule_id: str
    severity: str          # "FAIL", "WARN", "INFO"
    message: str
    fix: str
    reference: str = ""
    file_path: str = ""    # optional: specific file where issue was found
    line: int = 0          # optional: line number


@dataclass
class ScanResult:
    """Aggregated results from a full project scan."""
    platform: Platform
    project_type: str
    project_root: Path
    findings: List[Finding] = field(default_factory=list)
    scan_time_seconds: float = 0.0
    suppressed_count: int = 0
    gated_count: int = 0

    @property
    def fail_count(self) -> int:
        return sum(1 for f in self.findings if f.severity == "FAIL")

    @property
    def warn_count(self) -> int:
        return sum(1 for f in self.findings if f.severity == "WARN")

    @property
    def info_count(self) -> int:
        return sum(1 for f in self.findings if f.severity == "INFO")

    @property
    def has_failures(self) -> bool:
        return self.fail_count > 0

    @property
    def has_warnings(self) -> bool:
        return self.warn_count > 0

    def to_dict(self) -> dict:
        result = {
            "platform": self.platform.value,
            "project_type": self.project_type,
            "project_root": str(self.project_root),
            "scan_time_seconds": round(self.scan_time_seconds, 2),
            "summary": {
                "fail": self.fail_count,
                "warn": self.warn_count,
                "info": self.info_count,
            },
            "findings": [
                {
                    "id": f.rule_id,
                    "severity": f.severity,
                    "message": f.message,
                    "fix": f.fix,
                    "reference": f.reference,
                }
                for f in self.findings
            ],
        }
        if self.suppressed_count:
            result["summary"]["suppressed"] = self.suppressed_count
        if self.gated_count:
            result["summary"]["gated"] = self.gated_count
        return result


def run_scan(
    detection: DetectionResult,
    config: Optional[ScanConfig] = None,
    user_plan: str = "team",
) -> ScanResult:
    """Execute the appropriate scanner for the detected platform."""
    start = time.monotonic()

    logger.info("Scanning %s (%s) at %s", detection.platform.value, detection.project_type, detection.project_root)

    if detection.platform == Platform.IOS:
        from ..scanners.ios import scan
    elif detection.platform == Platform.ANDROID:
        from ..scanners.android import scan
    elif detection.platform == Platform.WEB:
        from ..scanners.web import scan
    else:
        raise ValueError(f"Unsupported platform: {detection.platform}")

    findings = scan(detection.project_root)

    # Run cross-platform / supply chain checks for all platforms
    from ..scanners.common import scan as common_scan
    findings.extend(common_scan(detection.project_root))

    logger.info("Found %d raw findings", len(findings))

    # Apply config: suppression + severity overrides
    suppressed_count = 0
    if config:
        original_count = len(findings)
        findings = config.filter_findings(findings)
        suppressed_count = original_count - len(findings)

    # Apply plan-based rule gating (Starter gets subset of rules)
    gated_count = 0
    if user_plan != "team":
        from ..rules.tiers import STARTER_RULES
        before_gating = len(findings)
        findings = [f for f in findings if f.rule_id in STARTER_RULES]
        gated_count = before_gating - len(findings)
        if gated_count:
            logger.info("Plan gating: %d finding(s) hidden (Starter plan)", gated_count)

    elapsed = time.monotonic() - start
    logger.info("Scan completed in %.2fs (%d findings, %d suppressed, %d gated)", elapsed, len(findings), suppressed_count, gated_count)

    return ScanResult(
        platform=detection.platform,
        project_type=detection.project_type,
        project_root=detection.project_root,
        findings=findings,
        scan_time_seconds=elapsed,
        suppressed_count=suppressed_count,
        gated_count=gated_count,
    )
