"""Module implements logic for rhcos image download"""
import subprocess
from subprocess import Popen, PIPE
from shutil import copyfileobj
from pathlib import Path
from typing import Tuple
from tempfile import NamedTemporaryFile


import gzip
import re
import logging
import json

import requests
from .utils import get_data

GITHUB_URL = "https://raw.githubusercontent.com/openshift/installer/{commit}/data/data/rhcos.json"


class CoreOsException(Exception):
    """CoreOsException represents error while executing installer in older version
    """
    def __init__(self, *args, **kwargs):
        super().__init__(self, *args, *kwargs)


def _get_coreos_json(installer: str) -> str:
    json_data = {}
    with Popen([installer, "coreos", "print-stream-json"], stdout=PIPE,
               stderr=subprocess.DEVNULL, universal_newlines=True) as proc:
        proc.wait()
        if proc.returncode != 0:
            raise CoreOsException("Installer doesn't support coreos subcommand")
        json_data = json.loads(proc.stdout.read())
    json_part = json_data["architectures"]["x86_64"]["artifacts"]["openstack"]
    release_str = json_part["release"]
    json_part = json_part["formats"]["qcow2.gz"]
    return json_part.get("disk", json_part)["location"], release_str


def get_commit(installer: str) -> Tuple[str, str]:
    """Function extracts source commit from installer,
    in order to find associated rhcos image"""
    version_str = ""
    commit_regex = re.compile(r"^.*commit (?P<commit>\w*)$", re.MULTILINE)
    with Popen([installer, "version"], stdout=PIPE, universal_newlines=True) as proc:
        version_str = proc.stdout.read()
    commits = commit_regex.findall(version_str)
    logging.info("Found commits by running installer %s", commits)
    return commits[0]


def _get_old_url(installer: str) -> Tuple[str, str]:
    commit = get_commit(installer)
    gh_data_link = GITHUB_URL.format(commit=commit)
    rhcos_json = requests.get(gh_data_link, allow_redirects=True)
    rhcos_data = json.loads(rhcos_json.content)
    return rhcos_data['baseURI'] + rhcos_data['images']['openstack']['path'], rhcos_data['buildid']


def get_url(installer: str) -> Tuple[str, str]:
    """Function builds url to rhcos image and version of
    rhcos iamge."""
    url, version = None, None
    try:
        url, version = _get_coreos_json(installer)
    except CoreOsException as ex:
        logging.debug(ex)
        url, version = _get_old_url(installer)
    return url, version


def _extract_gzip(buff: NamedTemporaryFile, target: str) -> Path:
    result = None
    with gzip.open(buff.name) as zip_file:
        result = Path(target)
        with result.open("wb") as output:
            copyfileobj(zip_file, output)
    return result


def download_image(image_url: str, image_file: str):
    """Main entrypoint for image download, function
    extracts url to rhcos image, downloads and extracts it
    to specified target"""
    directory = Path(image_file).parent
    # Check if the directory exists
    if not directory.exists():
        # If the directory does not exist, create it
        directory.mkdir(parents=True)
        logging.debug("Creating %s directory for download images", directory)
    else:
        logging.debug("Directory %s for images already exists", directory)
    res_file = get_data(image_url, image_file, _extract_gzip)
    return res_file
