#!/usr/bin/env python3

import subprocess
import argparse
from datetime import datetime

torrents = []

def get_torrent_list(args):
    try:
        process = subprocess.run(['transmission-remote', f'{args.host}:{args.port}', '-l'], capture_output=True, text=True, check=True)
        return process.stdout.splitlines()
    except subprocess.CalledProcessError as e:
        print(f"Command failed with return code {e.returncode}")
        print(f"Error output: {e.stderr}")
        exit()

def parse_torrent_list(list):
    id = 0
    for line in list:
        if id == 0:
            id += 1
            continue
        data = [x.strip() for x in line.split("  ") if x]
        print(line)

        if "Sum" in data[0]:
            continue

        torrent = {
            "id": id,
            "size": data[2],
            "ratio": data[6],
            "name": data[8]
        }
        print(torrent)
        torrents.append(torrent)
        id += 1

def add_torrent_info(args):
    try:
        process = subprocess.run(['transmission-remote', f'{args.host}:{args.port}', '-t', 'all', '-i'], capture_output=True, text=True, check=True)
        torrent_info = process.stdout.splitlines()
    except subprocess.CalledProcessError as e:
        print(f"Command failed with return code {e.returncode}")
        print(f"Error output: {e.stderr}")
        exit()

    id = 1  # Will be read from output.
    current_torrent = None
    for info in torrent_info:
        try:
            if "Id: " in info:
                print(info)
                id = int(info.split(": ")[1].strip())
                print(id)
                if 0 <= id-1 < len(torrents):
                    current_torrent = torrents[id-1]
                else:
                    current_torrent = None
                    continue

            if current_torrent is None:
                continue

            if "Date added" in info:
                date_str = info.split(": ")[1].strip()
                current_torrent["date_added"] = datetime.strptime(date_str, "%a %b %d %H:%M:%S %Y")
            elif "Latest activity" in info:
                date_str = info.split(": ")[1].strip()
                current_torrent["latest_activity"] = datetime.strptime(date_str, "%a %b %d %H:%M:%S %Y")
            elif "Source" in info:
                current_torrent["source"] = info.split(": ")[1].strip()
        except (IndexError, ValueError, KeyError) as e:
            print(f"Error processing torrent info: {e}")
            continue

def calculate_deletion_score(torrent):
    """
    Calculate a deletion score where higher scores indicate better deletion candidates.
    Factors considered:
    - Size (larger = higher score)
    - Age (older = higher score)
    - Inactivity period (longer inactive = higher score)
    - Ratio (lower = higher score, but with diminishing returns after 1.0)
    """
    now = datetime.now()
    #print(torrent)
    # Convert size to GB for scoring (assuming size is in format like "1.5 GB" or "700 MB")
    try:
        size_str = torrent.get('size', '0 GB')
        size_num = float(size_str.split()[0])
        if 'MB' in size_str:
            size_gb = size_num / 1024
        else:
            size_gb = size_num
    except (ValueError, IndexError):
        size_gb = 0

    # Calculate age in days
    try:
        age_days = (now - torrent.get('date_added', now)).days
    except (TypeError, AttributeError):
        age_days = 0

    # Calculate days since last activity
    try:
        inactive_days = (now - torrent.get('latest_activity', now)).days
    except (TypeError, AttributeError):
        inactive_days = 0

    try:
        ratio = float(torrent.get('ratio', '0'))
    except ValueError:
        ratio = 0

    # Calculate individual scores
    size_score = size_gb * 10  # points per GB
    age_score = min(age_days / 7, 52) * 1  # 1 points per week, max 1 year
    inactive_score = min(inactive_days / 7, 12) * 8  # 8 points per week inactive, max 12 weeks
    ratio_score = 1000 * (1 - min(ratio, 1.0))  # 100 points at ratio 0, 0 points at ratio >= 1

    # Combine scores
    total_score = size_score + age_score + inactive_score + ratio_score

    return total_score


def get_deletion_candidates(torrents, limit=10):
    """
    Sort torrents by deletion score and return the top candidates.
    """
    scored_torrents = [(t, calculate_deletion_score(t)) for t in torrents]
    sorted_torrents = sorted(scored_torrents, key=lambda x: x[1], reverse=True)

    # Print results
    print("\nTop deletion candidates:")
    print("-" * 120)
    print(f"{'Score':>8} {'Size':>10} {'Ratio':>6} {'Age(d)':>7} {'Inactive(d)':>11} {'Size_pts':>9} {'Age_pts':>8} {'Inact_pts':>9} {'Ratio_pts':>9} {'Name':<30}")
    print("-" * 120)

    for torrent, score in sorted_torrents[:limit]:
        now = datetime.now()
        age_days = (now - torrent['date_added']).days
        inactive_days = (now - torrent['latest_activity']).days

        size_str = torrent['size']
        size_num = float(size_str.split()[0])
        if 'MB' in size_str:
            size_gb = size_num / 1024
        else:
            size_gb = size_num

        size_score = size_gb * 10
        age_score = min(age_days / 7, 52) * 1
        inactive_score = min(inactive_days / 7, 12) * 8
        ratio = float(torrent['ratio'])
        ratio_score = 100 * (1 - min(ratio, 1.0))

        print(f"{score:8.1f} {torrent['size']:>10} {torrent['ratio']:>6} {age_days:>7d} {inactive_days:>11d} {size_score:>9.1f} {age_score:>8.1f} {inactive_score:>9.1f} {ratio_score:>9.1f} {torrent['name'][:30]}")

    return [t[0] for t in sorted_torrents]

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--host', default='localhost', help='Transmission host')
    parser.add_argument('--port', default='9091', help='Transmission port')
    parser.add_argument('--num', default='10', help='Amount of candidates to show')
    args = parser.parse_args()

    torrent_list = get_torrent_list(args)
    parse_torrent_list(torrent_list)
    add_torrent_info(args)
    #print(torrents)
    candidates = get_deletion_candidates(torrents, int(args.num))

if __name__ == "__main__":
    main()
