import shutil
import subprocess as sp
import os
import stat

from abc import ABC
from host import logger
from os.path import join as join_path


class ImageStorageHandler(ABC):
    def __init__(self, image_base, vm_base):
        self.image_base = image_base
        self.vm_base = vm_base

    def import_image(self, image_src, image_dest, protect=False):
        """Put an image at the destination
        :param src: An Image file
        :param dest: A path where :param src: is to be put.
        :param protect: If protect is true then the dest is protect (readonly etc)
        The obj must exist on filesystem.
        """

        raise NotImplementedError()

    def make_vm_image(self, image_path, path):
        """Copy image from src to dest

        :param src: A path
        :param dest: A path

        src and destination must be on same storage system i.e both on file system or both on CEPH etc.
        """
        raise NotImplementedError()

    def resize_vm_image(self, path, size):
        """Resize image located at :param path:
        :param path: The file which is to be resized
        :param size: Size must be in Megabytes
        """
        raise NotImplementedError()

    def delete_vm_image(self, path):
        raise NotImplementedError()

    def execute_command(self, command, report=True):
        command = list(map(str, command))
        try:
            output = sp.check_output(command, stderr=sp.PIPE)
        except Exception as e:
            if report:
                print(e)
                logger.exception(e)
            return False
        return True

    def vm_path_string(self, path):
        raise NotImplementedError()

    def qemu_path_string(self, path):
        raise NotImplementedError()

    def is_vm_image_exists(self, path):
        raise NotImplementedError()


class FileSystemBasedImageStorageHandler(ImageStorageHandler):
    def import_image(self, src, dest, protect=False):
        dest = join_path(self.image_base, dest)
        try:
            shutil.copy(src, dest)
            if protect:
                os.chmod(dest, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)
        except Exception as e:
            logger.exception(e)
            return False
        return True

    def make_vm_image(self, src, dest):
        src = join_path(self.image_base, src)
        dest = join_path(self.vm_base, dest)
        try:
            shutil.copy(src, dest)
        except Exception as e:
            logger.exception(e)
            return False
        return True

    def resize_vm_image(self, path, size):
        path = join_path(self.vm_base, path)
        command = ["qemu-img", "resize", "-f", "raw", path, "{}M".format(size)]
        if self.execute_command(command):
            return True
        else:
            self.delete_vm_image(path)
            return False

    def delete_vm_image(self, path):
        path = join_path(self.vm_base, path)
        try:
            os.remove(path)
        except Exception as e:
            logger.exception(e)
            return False
        return True

    def vm_path_string(self, path):
        return join_path(self.vm_base, path)

    def qemu_path_string(self, path):
        return self.vm_path_string(path)

    def is_vm_image_exists(self, path):
        path = join_path(self.vm_base, path)
        command = ["ls", path]
        return self.execute_command(command, report=False)


class CEPHBasedImageStorageHandler(ImageStorageHandler):
    def import_image(self, src, dest, protect=False):
        dest = join_path(self.image_base, dest)
        command = ["rbd", "import", src, dest]
        if protect:
            snap_create_command = ["rbd", "snap", "create", "{}@protected".format(dest)]
            snap_protect_command = ["rbd", "snap", "protect", "{}@protected".format(dest)]

            return self.execute_command(command) and self.execute_command(snap_create_command) and\
                self.execute_command(snap_protect_command)

        return self.execute_command(command)

    def make_vm_image(self, src, dest):
        src = join_path(self.image_base, src)
        dest = join_path(self.vm_base, dest)

        command = ["rbd", "clone", "{}@protected".format(src), dest]
        return self.execute_command(command)

    def resize_vm_image(self, path, size):
        path = join_path(self.vm_base, path)
        command = ["rbd", "resize", path, "--size", size]
        return self.execute_command(command)

    def delete_vm_image(self, path):
        path = join_path(self.vm_base, path)
        command = ["rbd", "rm", path]
        return self.execute_command(command)

    def vm_path_string(self, path):
        return join_path(self.vm_base, path)

    def qemu_path_string(self, path):
        return "rbd:{}".format(self.vm_path_string(path))

    def is_vm_image_exists(self, path):
        path = join_path(self.vm_base, path)
        command = ["rbd", "info", path]
        return self.execute_command(command, report=False)