from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path
from typing import List, Optional

import json

from cyclonedx.model.bom import Bom


@dataclass
class ParsedSbomFile:
    path: Path
    format: str
    component_count: int


def _parse_cyclonedx_json(path: Path) -> Optional[ParsedSbomFile]:
    data = json.loads(path.read_text(encoding="utf-8"))
    if data.get("bomFormat") != "CycloneDX":
        return None
    bom = Bom.from_json(data=data)
    count = len(bom.components or [])
    return ParsedSbomFile(path=path, format="cyclonedx_json", component_count=count)


def _parse_cyclonedx_xml(path: Path) -> Optional[ParsedSbomFile]:
    text = path.read_text(encoding="utf-8")
    if "<bom" not in text:
        return None
    bom = Bom.from_xml(data=text)
    count = len(bom.components or [])
    return ParsedSbomFile(path=path, format="cyclonedx_xml", component_count=count)


def _parse_spdx_json(path: Path) -> Optional[ParsedSbomFile]:
    data = json.loads(path.read_text(encoding="utf-8"))
    if not data.get("spdxVersion"):
        return None
    packages = data.get("packages") or []
    return ParsedSbomFile(path=path, format="spdx_json", component_count=len(packages))


def _parse_spdx_tag_value(path: Path) -> Optional[ParsedSbomFile]:
    text = path.read_text(encoding="utf-8", errors="ignore")
    count = 0
    for raw_line in text.splitlines():
        line = raw_line.strip()
        if line.startswith("PackageName:"):
            count += 1
    if count == 0:
        return None
    return ParsedSbomFile(path=path, format="spdx_tag_value", component_count=count)


def parse_sbom_file(path: Path) -> Optional[ParsedSbomFile]:
    suffix = path.suffix.lower()
    try:
        if suffix == ".json":
            # Try CycloneDX then SPDX JSON
            parsed = _parse_cyclonedx_json(path)
            if parsed:
                return parsed
            return _parse_spdx_json(path)
        if suffix == ".xml":
            return _parse_cyclonedx_xml(path)
        if suffix == ".spdx":
            # Tag-value format
            return _parse_spdx_tag_value(path)
    except Exception:
        return None
    return None

