# -*- coding: utf-8 -*-
# Copyright (C) 2012 Anaconda, Inc
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import absolute_import, division, print_function, unicode_literals

from base64 import b64encode
from collections import namedtuple
from errno import ENOENT
from functools import partial
from glob import glob
import hashlib
from itertools import chain
import json
from logging import getLogger
from os import listdir
from os.path import isdir, isfile, join
import conda_package_handling.api

from .link import islink, lexists
from .create import TemporaryDirectory
from ..._vendor.auxlib.collection import first
from ..._vendor.auxlib.compat import shlex_split_unicode
from ..._vendor.auxlib.ish import dals
from ...base.constants import PREFIX_PLACEHOLDER
from ...common.compat import open
from ...common.pkg_formats.python import (
    PythonDistribution, PythonEggInfoDistribution, PythonEggLinkDistribution,
    PythonInstalledDistribution,
)
from ...exceptions import CondaUpgradeError, CondaVerificationError, PathNotFoundError
from ...models.channel import Channel
from ...models.enums import FileMode, PackageType, PathType
from ...models.package_info import PackageInfo, PackageMetadata
from ...models.records import PathData, PathDataV1, PathsData, PrefixRecord

log = getLogger(__name__)

listdir = listdir
lexists, isdir, isfile = lexists, isdir, isfile


def yield_lines(path):
    """Generator function for lines in file.  Empty generator if path does not exist.

    Args:
        path (str): path to file

    Returns:
        iterator: each line in file, not starting with '#'

    """
    try:
        with open(path) as fh:
            for line in fh:
                line = line.strip()
                if not line or line.startswith('#'):
                    continue
                yield line
    except (IOError, OSError) as e:
        if e.errno == ENOENT:
            pass
        else:
            raise


def _digest_path(algo, path):
    if not isfile(path):
        raise PathNotFoundError(path)

    hasher = hashlib.new(algo)
    with open(path, "rb") as fh:
        for chunk in iter(partial(fh.read, 8192), b''):
            hasher.update(chunk)
    return hasher.hexdigest()


def compute_md5sum(file_full_path):
    return _digest_path('md5', file_full_path)


def compute_sha256sum(file_full_path):
    return _digest_path('sha256', file_full_path)


def find_first_existing(*globs):
    for g in globs:
        for path in glob(g):
            if lexists(path):
                return path
    return None


# ####################################################
# functions supporting read_package_info()
# ####################################################

def read_package_info(record, package_cache_record):
    epd = package_cache_record.extracted_package_dir
    icondata = read_icondata(epd)
    package_metadata = read_package_metadata(epd)
    paths_data = read_paths_json(epd)

    return PackageInfo(
        extracted_package_dir=epd,
        package_tarball_full_path=package_cache_record.package_tarball_full_path,
        channel=Channel(record.schannel or record.channel),
        repodata_record=record,
        url=package_cache_record.url,

        icondata=icondata,
        package_metadata=package_metadata,
        paths_data=paths_data,
    )


def read_index_json(extracted_package_directory):
    with open(join(extracted_package_directory, 'info', 'index.json')) as fi:
        return json.load(fi)


def read_index_json_from_tarball(package_tarball_full_path):
    with TemporaryDirectory() as tmpdir:
        conda_package_handling.api.extract(package_tarball_full_path, tmpdir, 'info')
        with open(join(tmpdir, 'info', 'index.json')) as f:
            json_data = json.load(f)