import requests
import click
import sys
import os
import esptool
import tempfile
import shutil

# -------------------------------------------------------------------------
# GLOBAL CONFIGURATION
# -------------------------------------------------------------------------
# GitHub Repositories
MEO_TELEMETRIX_GH_REPO = "MEO-3/thingbot-telemetrix-arduino"
MEO_FIRMWARE_GH_REPO = "MEO-3/meo-arduino"

FLASH_OFFSET = '0x0' # Offset for merge binary. Adjust if your firmware requires a specific flash layout.
# -------------------------------------------------------------------------

def get_latest_release_url(repo_slug, firmware_keyword):
    """
    Fetch the download URL for a specific firmware bin from GitHub Releases.
    """
    api_url = f"https://api.github.com/repos/{repo_slug}/releases/latest"
    try:
        click.echo(f"  -> Querying GitHub API: {api_url}")
        response = requests.get(api_url)
        response.raise_for_status()
        data = response.json()

        # Find asset matching keyword and ending in .bin
        for asset in data.get('assets', []):
            name = asset['name'].lower()
            if firmware_keyword.lower() in name and name.endswith('.bin'):
                return asset['browser_download_url'], asset['name'], asset['size']

        # Fallback: if specific keyword not found, try to find ANY .bin file
        for asset in data.get('assets', []):
            if asset['name'].endswith('.bin'):
                 return asset['browser_download_url'], asset['name'], asset['size']

        return None, None, 0
    except requests.exceptions.RequestException as e:
        click.echo(f"  -> API Error: {e}", err=True)
        return None, None, 0

def download_firmware(url, name, size):
    """
    Downloads the firmware file to a temporary directory.
    Returns (path_to_bin, path_to_temp_dir).
    """
    tmp_dir = tempfile.mkdtemp()
    bin_path = os.path.join(tmp_dir, name)
    
    click.echo(f"⬇Downloading {name} ({size} bytes)...")
    try:
        r = requests.get(url, stream=True)
        with open(bin_path, 'wb') as f:
            with click.progressbar(length=size) as bar:
                for chunk in r.iter_content(chunk_size=8192):
                    f.write(chunk)
                    bar.update(len(chunk))
        return bin_path, tmp_dir
    except Exception as e:
        click.echo(f"Download failed: {e}")
        shutil.rmtree(tmp_dir)
        return None, None

def flash_binary(target_port, baud, bin_path):
    """
    Wraps esptool to flash the binary to the target port.
    """
    click.echo(f"Flashing {target_port} @ {baud}bps...")
    
    # Construct arguments for esptool
    esptool_args = [
        '--port', target_port,
        '--baud', str(baud),
        '--before', 'default-reset',
        '--after', 'hard-reset',
        'write-flash',
        '-z',
        '--flash-mode', 'dio',
        '--flash-freq', '40m',
        '--flash-size', 'detect',
        FLASH_OFFSET, 
        bin_path
    ]

    # Save original sys.argv to restore later (esptool modifies it)
    original_argv = sys.argv
    sys.argv = ['esptool'] + esptool_args

    try:
        esptool.main()
        click.echo("\nFirmware update successful!")
        return True
    except Exception as e:
        click.echo(f"\nFlashing error: {e}")
        return False
    finally:
        # Restore sys.argv
        sys.argv = original_argv