import os
import zipfile
import plistlib
import re
import shutil
import json

def extract_ipa_info(ipa_path, img_dir, base_url):
    """
    Extract bundle identifier, app metadata, and app icon from an IPA file.

    Args:
        ipa_path (str): Path to the IPA file.
        img_dir (str): Directory to save extracted icons.
        base_url (str): Base URL for serving files.

    Returns:
        dict: App metadata including icon path, or None if extraction fails.
    """
    try:
        # Ensure the image directory exists
        os.makedirs(img_dir, exist_ok=True)

        with zipfile.ZipFile(ipa_path, 'r') as ipa:
            # Find the Info.plist file inside the .app directory
            info_plists = [f for f in ipa.namelist() if 'Payload/' in f and f.endswith('.app/Info.plist')]

            if not info_plists:
                print(f"No Info.plist found in {ipa_path}")
                return None

            # Read the Info.plist
            with ipa.open(info_plists[0]) as plist_file:
                try:
                    plist_data = plistlib.load(plist_file)
                except Exception as e:
                    print(f"Error parsing plist in {ipa_path}: {e}")
                    return None

            # Extract key information
            bundle_id = plist_data.get('CFBundleIdentifier', '')

            # Use the IPA filename without extension as the app name
            app_name = os.path.splitext(os.path.basename(ipa_path))[0]

            # Get version, with fallbacks
            version = (
                plist_data.get('CFBundleShortVersionString') or
                plist_data.get('CFBundleVersion') or
                '1.0'
            )

            # Find and extract app icon
            icon_path = None
            try:
                # Look for icon files in the app bundle
                icon_names = plist_data.get('CFBundleIcons', {}).get('CFBundlePrimaryIcon', {}).get('CFBundleIconFiles', [])
                if not icon_names:
                    icon_names = plist_data.get('CFBundleIconFiles', [])
                
                # Use icon names to find icons in the IPA
                for icon_name in icon_names:
                    icon_candidates = [f for f in ipa.namelist() if icon_name in f and 'Payload/' in f]
                    if icon_candidates:
                        icon_in_ipa = icon_candidates[0]

                        # Create output icon path
                        icon_filename = f"{bundle_id}.png"
                        icon_path = os.path.join(img_dir, icon_filename)

                        # Extract icon
                        with ipa.open(icon_in_ipa) as icon_file:
                            with open(icon_path, 'wb') as output_icon:
                                shutil.copyfileobj(icon_file, output_icon)
                        break  # Stop after finding first matching icon
            except Exception as e:
                print(f"Could not extract icon for {app_name}: {e}")

            return {
                'bundleIdentifier': bundle_id,
                'name': app_name,  # Use the filename as the app name
                'version': version,
                'iconPath': icon_path,
                'iconURL': f"{base_url}/img/{bundle_id}.png"  # Restore original icon URL format
            }
    except Exception as e:
        print(f"Error processing {ipa_path}: {e}")
        return None

def update_repo_json(repo_data, ipa_filename, app_info, base_url):
    """
    Update the repo.json file with app information.

    Args:
        repo_data (dict): Existing repository data.
        ipa_filename (str): Filename of the IPA.
        app_info (dict): Extracted app information.
        base_url (str): Base URL for serving files.

    Returns:
        dict: Updated repository data.
    """
    # Construct download URL for the IPA
    ipa_download_url = f"{base_url}/ipas/{ipa_filename}"

    # Create or update app entry
    app_entry = {
        'name': app_info['name'],  # Use the name from the IPA filename
        'bundleIdentifier': app_info['bundleIdentifier'],
        'developerName': f"{app_info['name']} Developer",  # Placeholder for developer name
        'version': app_info['version'],
        'versionDate': "2024-10-27",  # Placeholder for version date
        'downloadURL': ipa_download_url,
        'localizedDescription': f"{app_info['name']} description",  # Placeholder for description
        'iconURL': app_info['iconURL'],
        'tintColor': "FFC300",  # Placeholder for tint color
        'size': 0,  # Placeholder for size (you may want to calculate this)
        'screenshotURLs': []  # Placeholder for screenshot URLs
    }

    # Update repository data
    if 'apps' not in repo_data:
        repo_data['apps'] = []  # Initialize the apps list if it doesn't exist

    repo_data['apps'].append(app_entry)

    return repo_data

def create_repo_json(ipa_files, img_dir, base_url):
    """
    Create a new repository JSON structure from IPA files.

    Args:
        ipa_files (list): List of IPA filenames.
        img_dir (str): Directory to save extracted icons.
        base_url (str): Base URL for serving files.

    Returns:
        dict: New repository data.
    """
    repo_data = {
        "name": "Inject repo",  # Set your repository name
        "identifier": "com.idk.inject",  # Set your identifier
        "subtitle": ".",  # Set subtitle
        "iconURL": f"{base_url}/img/RepoIcon.png",  # Set repo icon URL
        "website": base_url,  # Set website URL
        "sourceURL": f"{base_url}/repo.json",  # Set source URL for the repo
        "tintColor": "FFC300",  # Example color
        "featuredApps": [],  # You can populate this later
        "apps": []  # Initialize with an empty apps list
    }

    # Process each IPA file
    for ipa_filename in ipa_files:
        ipa_path = os.path.join(ipa_dir, ipa_filename)
        print(f"\nProcessing {ipa_filename}...")

        # Extract IPA information
        app_info = extract_ipa_info(ipa_path, img_dir, base_url)

        # Update repo.json if info extracted successfully
        if app_info:
            print("Extracted App Information:")
            print(f"App Name: {app_info['name']}")
            print(f"Bundle Identifier: {app_info['bundleIdentifier']}")
            print(f"Version: {app_info['version']}")
            if app_info['iconPath']:
                print(f"Icon saved to: {app_info['iconPath']}")
                print(f"Icon URL: {app_info['iconURL']}")

            # Update repository data
            repo_data = update_repo_json(repo_data, ipa_filename, app_info, base_url)
        else:
            print(f"Failed to extract information from {ipa_filename}")

    return repo_data

def main():
    # Predefined directories and base URL
    global ipa_dir
    ipa_dir = './ipas'
    img_dir = './img'
    base_url = 'https://homepi.cc'

    # Ensure directories exist
    os.makedirs(ipa_dir, exist_ok=True)
    os.makedirs(img_dir, exist_ok=True)

    # Find all IPA files in the directory
    ipa_files = [f for f in os.listdir(ipa_dir) if f.endswith('.ipa')]

    if not ipa_files:
        print(f"No IPA files found in {ipa_dir}")
        return

    # Create a new repository data structure
    repo_data = create_repo_json(ipa_files, img_dir, base_url)

    # Save updated repository data
    with open('./repo.json', 'w') as f:
        json.dump(repo_data, f, indent=2)

    print("\nRepository data updated in repo.json")

if __name__ == "__main__":
    main()
