import os
import subprocess

import urllib.request
import zipfile
import configparser

import inworld
import unreal

def get_config():
    if not os.path.exists(inworld.extras_config):
        with open(inworld.extras_config, 'w') as configfile:
            pass  # Create an empty file if one does not exist

    config = configparser.ConfigParser()
    config.read(inworld.extras_config)
    
    if not config.has_section("extras"):
        # Add the section and the default values
        config.add_section("extras")
        config.set("extras", "version", "0.0.0")
        
        # Write changes back to the file
        with open(inworld.extras_config, 'w') as file:
            config.write(file)

    return dict(config.items('extras'))

def update_config(section: str, key: str, val: str):
    config = configparser.ConfigParser()
    config.read(inworld.extras_config)
    # Set the config value
    config.set(section, key, val)
    # Write changes back to the file
    with open(inworld.extras_config, 'w') as file:
        config.write(file)
    

def download_extras():
    unreal.log(f"Downloading {inworld.extras_filename}...")

    # Open the URL
    response = urllib.request.urlopen(inworld.extras_url)
    total_size = int(response.getheader('Content-Length').strip())
    bytes_downloaded = 0
        
    # Create task bar
    with unreal.ScopedSlowTask(total_size, f"Downloading inworld extras...") as slow_task:
        # Show progress, allow cancelation
        slow_task.make_dialog(True)

        # Open the file to write to
        with open(inworld.extras_filename, 'wb') as file:
            while not slow_task.should_cancel() and (chunk := response.read(8192)):
                file.write(chunk)
                bytes_downloaded += len(chunk)
                    
                # Convert progress to readable format
                total_str = inworld.bytes_to_str(total_size)
                downloaded_str = inworld.bytes_to_str(bytes_downloaded)
                # Update task bar
                slow_task.enter_progress_frame(len(chunk), f"Downloading inworld extras... ({downloaded_str}/{total_str})")
                
            # Cleanup partially downloaded file
            if slow_task.should_cancel():
                file.close()
                os.remove(inworld.extras_filename)

def unzip_extras():
    unreal.log(f"Unzipping {inworld.extras_filename}...")

    # Open the zip
    with zipfile.ZipFile(inworld.extras_filename, 'r') as zip_ref:
        # Get a list of all file names in the zip
        all_files = zip_ref.namelist()
        total_files = len(all_files)

        # Create task bar
        with unreal.ScopedSlowTask(total_files, f"Unzipping inworld extras...") as slow_task:
            # Show progress, do not allow cancelation
            slow_task.make_dialog(False)
            for index, file in enumerate(all_files):
                # Extract the current file
                zip_ref.extract(file, inworld.extras_path)

                # Update task bar
                slow_task.enter_progress_frame(1, f"Unzipping inworld extras... ({index+1}/{total_files})")
        
    # Cleanup zip file
    os.remove(inworld.extras_filename)

if __name__ == "__main__":
    if not os.path.isdir(inworld.extras_path):
        os.makedirs(inworld.extras_path)
    config = get_config()
    if config['version'] != inworld.extras_version:
        download_extras()
        if os.path.exists(inworld.extras_filename):
            unzip_extras()
        update_config("extras", "version", inworld.extras_version)
