import csv
import hashlib
from pathlib import Path
import json
from collections import Counter
import statistics


def load_data(file_path):
    """Loads JSON data from a specified file path."""
    with open(file_path, "r") as f:
        return json.load(f)


def analyze_packages(results):
    """Analyzes package data to extract relevant statistics."""
    packages_with_pyc_counts = {"sdist": [], "wheel": [], "egg": [], "zip": []}
    packages_with_pyc_names = set()
    pyc_file_versions = []
    not_run_because_extension = []

    for package_name, package_data in results.items():
        # Get versions of pyc files
        for artifact_type in ["sdist", "wheel", "egg", "zip"]:
            files = package_data.get(artifact_type, {}).get("files", [])
            if files:
                packages_with_pyc_counts[artifact_type].append(len(files))
                packages_with_pyc_names.add(package_name)
                pyc_file_versions.extend([file["version"] for file in files])

        # Get file suffixes that have been ignored
        analysis_meta = package_data.get("meta", {}).get("analysis", {})
        status = analysis_meta.get("other", {}).get("status", "")
        if not status == "not run":
            not_run_because_extension.append(status.split(".")[-1])

    return (
        packages_with_pyc_counts,
        packages_with_pyc_names,
        pyc_file_versions,
        not_run_because_extension,
    )


def dump_dataset_as_csv(results):
    """Dumps the csv of analyzed artifacts for replication."""
    headers = ["artifact", "purl", "hash"]

    output_path = Path("analyzed_artifacts.csv")

    with output_path.open("w", newline="", encoding="utf-8") as csvfile:
        writer = csv.writer(csvfile)
        writer.writerow(headers)

        for package_name, package_data in results.items():
            # we only looked at these artifact types for evaluation
            for artifact_type in ["sdist", "wheel", "egg"]:
                files = package_data.get(artifact_type, {}).get("files", [])

                if files:
                    version = package_data["meta"]["version"]
                    base_path = Path(package_data["meta"]["base_path"])

                    # Construct file path
                    filename = Path(package_data[artifact_type]["filepath"]).name
                    filepath = base_path / version / filename

                    # Construct purl
                    # https://github.com/package-url/purl-spec
                    purl = f"pkg:pypi/{package_name}@{version}?file_name={filename}"

                    # Calculate hash
                    with filepath.open("rb", buffering=0) as f:
                        digest = hashlib.file_digest(f, "sha256").hexdigest()

                    writer.writerow([artifact_type, purl, digest])


def print_statistics(
    total_packages, pyc_package_names, pyc_counts, versions, other_statuses
):
    """Prints a structured, high-density summary of the analysis."""

    # 1. Header and High-Level Summary
    print("\n" + "═" * 85)
    print(f"{'PYTHON PACKAGE ANALYSIS SUMMARY':^85}")
    print("═" * 85)

    summary_stats = [
        ("Total packages analyzed", total_packages),
        ("Packages containing .pyc files", len(pyc_package_names)),
        ("Clean packages (no .pyc)", total_packages - len(pyc_package_names)),
    ]

    for label, value in summary_stats:
        print(f" {label:<40}: {value:>10}")

    # 2. Artifact Statistics Table
    print("\n" + "─" * 85)
    header = f"{'ARTIFACT TYPE':<15} {'FOUND':>8} {'AVG':>8} {'MED':>8} {'STDEV':>8} {'MIN/MAX':>12}"
    print(header)
    print("─" * 85)

    for artifact_type, counts in pyc_counts.items():
        if not counts:
            continue

        artifact_name = artifact_type.replace("sdist", "tar.gz")

        # Calculate Stats
        mean_val = statistics.mean(counts)
        med_val = statistics.median(counts)
        min_val = min(counts)
        max_val = max(counts)

        # Stdev requires at least two data points
        stdev_val = statistics.stdev(counts) if len(counts) > 1 else 0.0

        print(
            f"{artifact_name:<15} "
            f"{len(counts):>8} "
            f"{mean_val:>8.2f} "
            f"{med_val:>8.0f} "
            f"{stdev_val:>8.2f} "
            f"{min_val:>5.0f}/{max_val:<5.0f}"
        )

    # 3. Version Distribution
    if versions:
        print("\n" + "─" * 85)
        print(f"{'PYC PYTHON VERSIONS DETECTED':<45} {'COUNT':>15} {'%':>12}")
        print("─" * 85)

        version_counts = Counter(versions)
        total_v = len(versions)
        for version, count in version_counts.most_common():
            pct = (count / total_v) * 100
            print(f"{str(version):<45} {count:>15} {pct:>11.2f}%")

    # 4. Warnings / Weird Suffixes
    if other_statuses:
        print("\n" + "!" * 85)
        print(f"{'SKIPPED FILES (UNRECOGNIZED SUFFIX)':^85}")
        print("!" * 85)
        for status, count in Counter(other_statuses).items():
            print(f"  • {status:<60} {count:>10}")

    print("═" * 85 + "\n")


def main():
    results = load_data("results.json")

    total_packages = len(results)
    (pyc_counts, pyc_package_names, pyc_versions, other_statuses) = analyze_packages(
        results
    )

    print_statistics(
        total_packages, pyc_package_names, pyc_counts, pyc_versions, other_statuses
    )

    dump_dataset_as_csv(results)


if __name__ == "__main__":
    main()
