#!/usr/bin/env python3

import os
import re
import subprocess
import sys
from pathlib import Path
from portage.versions import vercmp

def get_ebuilds(repo_path):
    """Find all ebuild files in the repository."""
    ebuild_files = list(Path(repo_path).glob('*/*/*.ebuild'))
    packages = {}

    for ebuild in ebuild_files:
        category = ebuild.parent.parent.name
        package_name = ebuild.parent.name
        version = ebuild.name.replace(f"{package_name}-", "").replace(".ebuild", "")

        if (category, package_name) not in packages:
            packages[(category, package_name)] = []

        packages[(category, package_name)].append((version, ebuild))

    return packages

def get_upstream_info(category, package_name, repo_path):
    """Get upstream location and available versions from equery meta output."""
    try:
        result = subprocess.run(
            ['equery', 'meta', f"{category}/{package_name}"],
            capture_output=True,
            text=True,
            check=True
        )

        location = None
        versions = []
        repo_name = None

        for line in result.stdout.split('\n'):
            if line.startswith('Location:'):
                location = line.split(':', 1)[1].strip()
            elif line.startswith('Keywords:'):
                # Format: "Keywords:    3.0.67-r1:0:"
                parts = line.split()
                if len(parts) >= 2:
                    version_part = parts[1]  # "3.0.67-r1:0:"
                    version = version_part.split(':')[0]
                    versions.append(version)

        # Extract repository name from location path
        if location:
            # Location format: /var/db/repos/gentoo/sys-apps/portage
            # or /var/db/repos/local/dev-util/intel_clc
            path_parts = location.split('/')
            if len(path_parts) >= 5 and path_parts[3] == 'repos':
                repo_name = path_parts[4]  # gentoo, local, etc.

        # Check if this package exists in the main Gentoo repository
        # or if it's only in our overlay
        repo_path_abs = Path(repo_path).resolve()
        location_path = Path(location) if location else None

        # Package is only in our overlay if the location is within our repo
        is_only_in_overlay = (location_path and
                             (repo_path_abs in location_path.parents or
                              location_path.parent.parent == repo_path_abs))

        return location, versions, repo_name, is_only_in_overlay

    except subprocess.CalledProcessError:
        return None, [], None, False  # Package might not exist upstream
    except FileNotFoundError:
        print("Error: equery command not found. Please install app-portage/gentoolkit.", file=sys.stderr)
        sys.exit(1)

def is_version_obsolete(ebuild_version, upstream_versions, repo_path, upstream_location, is_only_in_overlay):
    """Check if ebuild version is obsolete compared to upstream versions."""
    # If package only exists in our overlay, it can't be obsolete
    if is_only_in_overlay:
        return False

    if not upstream_versions or not upstream_location:
        return False

    # Check if upstream location is outside our repo
    upstream_path = Path(upstream_location)
    repo_path_abs = Path(repo_path).resolve()

    # If upstream is in our repo, skip comparison
    try:
        if repo_path_abs in upstream_path.parents or upstream_path == repo_path_abs:
            return False
    except:
        pass  # If path comparison fails, continue with version check

    # Find the highest upstream version
    if not upstream_versions:
        return False

    highest_upstream = upstream_versions[0]
    for version in upstream_versions[1:]:
        try:
            if vercmp(version, highest_upstream) > 0:
                highest_upstream = version
        except:
            continue  # Skip versions that can't be compared

    # Compare our version with the highest upstream
    try:
        return vercmp(ebuild_version, highest_upstream) < 0
    except:
        return False

def list_obsolete(repo_path=Path('.')):
    """Main function to list obsolete packages."""
    repo_path_abs = Path(repo_path).resolve()
    packages = get_ebuilds(repo_path_abs)
    obsolete_packages = {}

    for (category, package_name), ebuilds in packages.items():
        upstream_location, upstream_versions, repo_name, is_only_in_overlay = get_upstream_info(
            category, package_name, repo_path_abs
        )

        # Skip packages that only exist in our overlay
        if is_only_in_overlay:
            continue

        # Skip if no upstream info or no versions found
        if not upstream_location or not upstream_versions:
            continue

        obsolete_ebuilds = []
        all_obsolete = True

        for version, ebuild_path in ebuilds:
            if is_version_obsolete(version, upstream_versions, repo_path_abs,
                                 upstream_location, is_only_in_overlay):
                obsolete_ebuilds.append(ebuild_path)
            else:
                all_obsolete = False

        if obsolete_ebuilds:
            if all_obsolete:
                obsolete_packages[(category, package_name)] = ebuilds[0][1].parent
            else:
                obsolete_packages[(category, package_name)] = obsolete_ebuilds

    return obsolete_packages

def main():
    if len(sys.argv) < 3 or sys.argv[1] != 'list' or sys.argv[2] != 'obsolete':
        print("Usage: ebuild-repo-tools.py list obsolete [REPO_PATH]")
        print("  REPO_PATH: Path to the overlay repository (default: current directory)")
        sys.exit(1)

    repo_path = Path(sys.argv[3] if len(sys.argv) > 3 else '.')

    if not os.path.exists(repo_path):
        print(f"Error: Repository path '{repo_path}' does not exist.", file=sys.stderr)
        sys.exit(1)

    try:
        obsolete = list_obsolete(repo_path)

        if not obsolete:
            print("No obsolete packages found.")
            return

        repo_path = repo_path.absolute()
        for (category, package_name), paths in obsolete.items():
            if isinstance(paths, Path):  # Directory (all ebuilds obsolete)
                print(paths.relative_to(repo_path))
            else:  # List of ebuild paths
                for path in paths:
                    print(path)

    except KeyboardInterrupt:
        print("\nOperation cancelled by user.", file=sys.stderr)
        sys.exit(1)
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)

if __name__ == '__main__':
    main()
