# Copyright (C) 2022 Thomas Hoppe (h0bB1T). All rights reserved.
#
# Unauthorized copying of this file via any medium is strictly prohibited.
# Proprietary and confidential.

import bpy, os, subprocess, io, json, tempfile, uuid

from typing import Any, Dict, List

from ..utils.dev import inf, log_exception


def run_blender(args: List[str]):
    """
    Runs Blender in background.
    """
    args.insert(0, bpy.app.binary_path)
    inf(f'Start: {" ".join(args)}')
    subprocess.Popen(args, universal_newlines=True).wait()


def os_path(blender_path: str) -> str:
    """
    Return file file in blender format as os path.
    """
    return os.path.abspath(bpy.path.abspath(blender_path))


def unified_path(path_or_file) -> str:
    """
    As c:\\bla is the same as C:/blA/, we need to bring 
    paths on a single notation, when used as dict-key.
    """
    return os.path.normcase(os_path(path_or_file))


def write_json(filename: str, data: Dict[str, Any]):
    try:
        with io.open(filename, mode='w', encoding='utf-8') as dest:
            json.dump(data, dest, indent=4)
    except Exception as ex:
        log_exception(ex, context_msg=f'Failed to write json: {filename}')


def read_json(filename: str) -> Dict[str, Any]:
    try:
        with io.open(filename, mode='r', encoding='utf-8') as src:
            return json.load(src)
    except Exception as ex:
        log_exception(ex, context_msg=f'Failed to read json: {filename}')
    return dict()


def decode_json(tag: str) -> Dict[str, Any]:
    if tag:
        return json.loads(tag)
    else:
        return {}    


def platform_addon_dir() -> str:
    """
    Returns the storage directory for the current platform.
    """
    path = ''
    if os.name == 'nt':
        base = os.environ.get('LOCALAPPDATA') or os.path.expanduser('~\\AppData\\Local')
        path = os.path.join(base, '.storage', 'wns')
    else:
        path = os.path.join(os.path.expanduser('~'), '.local', 'share', 'wns')
    if not os.path.exists(path):
        os.makedirs(path, exist_ok=True)

    return path


def addon_info_exists() -> bool:
    """
    Returns true if the addon info file exists.
    """
    return os.path.exists(os.path.join(platform_addon_dir(), 'bl_info.json'))


def get_addon_info() -> Dict[str, Any]:
    """
    Returns the addon info dict from bl_info.
    """
    return read_json(os.path.join(platform_addon_dir(), 'bl_info.json'))
    

def set_addon_info(info: Dict[str, Any]):
    """
    Stores the addon info dict from bl_info.
    """
    path = os.path.join(platform_addon_dir(), 'bl_info.json')
    d = os.path.dirname(path)

    fd, tmp = tempfile.mkstemp(prefix='.tmp_', dir=d)
    try:
        with os.fdopen(fd, 'w', encoding='utf-8') as f:
            json.dump(info, f, separators=(',', ':'))
        os.replace(tmp, path)
    finally:
        try:
            if os.path.exists(tmp):
                os.remove(tmp)
        except Exception:
            pass


class TempFile:
    """
    Creates a temp file using 'with' statement and deletes (RAII).
    """
    def __init__(self, ext: str):
        self.name = os.path.join(tempfile.gettempdir(), f'awp_{uuid.uuid4().hex}.{ext}')


    def __enter__(self):
        return self.name
        

    def __exit__(self, type, value, tb):
        if os.path.exists(self.name):
            try: 
                os.remove(self.name)
            except Exception as e:
                log_exception(e, context_msg='Failed to delete temp file')                   
