import csv
import os
import shutil
from configparser import ConfigParser

import yaml

from flyers import assets


class FileSizeUnit(object):
    B = 0
    KB = 1
    MB = 2
    GB = 3
    TB = 4
    PB = 5


class File(object):
    def __init__(self, path):
        assets.check_blank(path, 'path')
        self.path = path

    def is_file(self):
        return is_file(self.path)

    def is_dir(self):
        return not is_file(self.path)

    def rm(self):
        if self.is_file():
            rm_file(self.path)
        else:
            rmdir(self.path)

    def ls(self) -> (str, list):
        if not self.is_dir():
            return 'Not a directory: {}'.format(self.path), None
        return None, os.listdir(self.path)

    def read(self):
        return read_file(self.path)

    def write(self, new_content):
        return write_file(self.path, new_content)

    def append(self, new_lines):
        return append_file(self.path, new_lines)

    def md5(self):
        return get_md5(self.path)

    def size(self, unit):
        return get_file_size(self.path, unit)


def is_file(filename: str) -> bool:
    assets.check_blank(filename, 'filename')
    return os.path.isfile(filename)


def mv(src: str, dst: str):
    assets.check_blank(src, 'src')
    assets.check_blank(dst, 'dst')
    return os.rename(src, dst)


def read_file(filename: str, encoding='utf-8') -> str:
    assets.check_blank(filename, 'filename')
    with open(filename, encoding=encoding) as f:
        return f.read()


def read_lines(filename: str, encoding='utf-8') -> list[str]:
    assets.check_blank(filename, 'filename')
    with open(filename, encoding=encoding) as f:
        return f.readlines()


def read_and_splitlines(filename: str, encoding='utf-8') -> list[str]:
    assets.check_blank(filename, 'filename')
    with open(filename, encoding=encoding) as f:
        return f.read().splitlines()


def write_file(filename: str, data: str, encoding='utf-8'):
    assets.check_blank(filename, 'filename')
    with open(filename, 'w+', encoding=encoding) as f:
        f.write(data)


def append_file(filename: str, new_lines: str, encoding='utf-8'):
    assets.check_blank(filename, 'filename')
    with open(filename, 'a', encoding=encoding) as f:
        f.write(new_lines)


def update_file(filename: str, func):
    assets.check_blank(filename, 'filename')
    assets.check_blank(func, 'func')

    data = read_file(filename)
    new_data = func(data)
    write_file(filename, new_data)


def rm_file(filename: str):
    assets.check_blank(filename, 'filename')
    os.remove(filename)


def get_files(base_dir: str, endswith: str = None):
    assets.check_blank(base_dir, 'base_dir')

    result = []
    for f in os.listdir(base_dir):
        file_path = os.path.join(base_dir, f)
        if os.path.isfile(file_path) and (not endswith or f.endswith(endswith)):
            result.append(file_path)
    return result


def get_md5(filename: str) -> str:
    assets.check_blank(filename, 'filename')

    files_md5 = os.popen('md5 %s' % filename).read().strip()
    file_md5 = files_md5.replace('MD5 (%s) = ' % filename, '')
    return file_md5


def get_file_size(filename: str, unit: int) -> float:
    assets.check_blank(filename, 'filename')

    size_units = FileSizeUnit.__dict__
    if unit not in size_units.values():
        raise TypeError('No supports this unit')

    size = os.path.getsize(filename)
    for i in range(unit):
        size = size / float(1024)

    return size


def mkdir(d: str):
    os.mkdir(d)


def rmdir(d: str):
    shutil.rmtree(d)


def copy_dir(src: str, dst: str) -> None:
    for files in os.listdir(src):
        name = os.path.join(src, files)
        back_name = os.path.join(dst, files)
        if os.path.isfile(name):
            if os.path.isfile(back_name):
                if get_md5(name) != get_md5(back_name):
                    shutil.copy(name, back_name)
            else:
                shutil.copy(name, back_name)
        else:
            if not os.path.isdir(back_name):
                os.makedirs(back_name)
            copy_dir(name, back_name)


def read_yaml_file(filename: str) -> dict:
    assets.check_blank(filename, 'filename')
    return yaml.load(read_file(filename), yaml.FullLoader)


def read_csv_file(filename: str, delimiter: str = ' ', quote: str = '|'):
    assets.check_blank(filename, 'filename')
    with open(filename, newline='') as csvfile:
        csv.reader(csvfile, delimiter=delimiter, quotechar=quote)


def read_ini_file(filename: str) -> dict:
    assets.check_blank(filename, 'filename')
    conf = ConfigParser()
    conf.read(filename)
    result = {}
    for k, v in conf.items():
        item = {}
        for kk, vv in v.items():
            item.update({kk: vv})
        result.update({k: item})
    return result
