from __future__ import annotations

from dataclasses import dataclass
from datetime import datetime, timezone
from pathlib import Path
from typing import Optional

from . import __version__
from .discovery import DiscoveryResult, discover_project
from .reporters.json import render_json_report
from .reporters.text import render_text_report
from .scoring import ScoreBreakdown, compute_scores


@dataclass
class ScanConfig:
    project_root: Path
    sbom_path: Optional[Path]
    output_format: str
    output_path: Optional[Path]


def perform_scan(config: ScanConfig) -> None:
    discovery: DiscoveryResult = discover_project(config.project_root, config.sbom_path)
    scores: ScoreBreakdown = compute_scores(discovery)

    report = {
        "meta": {
            "scannerVersion": __version__,
            "projectPath": str(config.project_root),
            "timestamp": datetime.now(timezone.utc).isoformat(),
        },
        "scores": {
            "overall": scores.overall,
            "sbom": scores.sbom_score,
            "vulnerabilities": scores.vuln_score,
            "practices": scores.practices_score,
        },
        "sbom": {
            "found": discovery.sbom_found,
            "files": [
                {
                    "path": str(f.path),
                    "format": f.format,
                    "componentCount": f.component_count,
                }
                for f in discovery.sbom_files
            ],
        },
        "signals": {
            "hasSecurityMd": discovery.has_security_md,
            "hasDocsSecuritySection": discovery.has_docs_security_section,
            "hasDependabot": discovery.has_dependabot,
        },
        "recommendations": scores.recommendations,
    }

    if config.output_format == "json":
        output = render_json_report(report)
        if config.output_path:
            config.output_path.write_text(output, encoding="utf-8")
        else:
            print(output)
    else:
        text = render_text_report(report, discovery, scores)
        print(text)

