import datetime
import os
import shutil
import logging
from sys import getfilesystemencoding

from django.utils.decorators import method_decorator

from django_http_auth.decorators import http_basic_auth

from djangodav.acls import FullAcl
from djangodav.base.resources import BaseDavResource, MetaEtagMixIn
from djangodav.locks import DummyLock
from djangodav.utils import url_join
from djangodav.views import DavView

from procat2.models import Catalog

# from procat2.settings import ASSET_DIR

log = logging.getLogger(__name__)

fs_encoding = getfilesystemencoding()


@method_decorator(http_basic_auth, name='dispatch')
class MarkupDavView(DavView):

    def __init__(self):
        super(DavView, self).__init__(resource_class=MarkupDavResource, lock_class=DummyLock, acl_class=FullAcl)


class MarkupDavResource(MetaEtagMixIn, BaseDavResource):
    ROOT_FOLDER = ''
    MY_CATS_FOLDER = 'My Catalogs'
    MARKUP_SUBMIT_FOLDER = 'For Markup'
    #root = '/opt/imagebank/mkbeta/webdav' # TODO replace with settings var

    def __init__(self, path=None, user=None):
        super().__init__(path)
        self.user = user

    def __str__(self):
        return f"<MarkupDavResource '{self.user}' '{self.path}'>"

    def get_children(self):
        """Return an iterator of all direct children of this resource."""
        # make sure the current object is a directory
        path = self.get_path()
        log.info(f"get_children of '{path}'")

        children = []
        if path == '/':
            children = [self.MY_CATS_FOLDER, self.MARKUP_SUBMIT_FOLDER]
        elif path == f'/{self.MY_CATS_FOLDER}/':
            children = self.user_catalogs()
        elif path == f'/{self.MARKUP_SUBMIT_FOLDER}/':
            children = None
        # else:
        #     path = self.get_abs_path()
        #     if os.path.isdir(path):
        #         children = os.listdir(path)

        for child in children:
            is_unicode = isinstance(child, str)
            if not is_unicode:
                child = child.decode(fs_encoding)
            child_resource = self.clone(path=url_join(*(self.path + [child])), user=self.user)
            log.info(f'returning kid {child_resource}')
            yield child_resource

    def user_catalogs(self):
        cats = Catalog.objects.filter(owner=self.user).order_by('-updated')
        return [c.name for c in cats]

    def get_abs_path(self):
        """Return the absolute path of the resource. Used internally to interface with
        an actual file system. If you override all other methods, this one will not
        be used."""
        return os.path.join(self.root, *self.path)

    @property
    def getcontentlength(self):
        """Return the size of the resource in bytes."""
        if self.is_collection:
            return 0
        else:
            return os.path.getsize(self.get_abs_path())

    def get_created(self):
        """Return the create time as datetime object."""
        if self.is_collection:
            return datetime.datetime.now() # TODO last created time of object in there?
        else:
            return datetime.datetime.fromtimestamp(os.stat(self.get_abs_path()).st_ctime)

    def get_modified(self):
        """Return the modified time as datetime object."""
        if self.is_collection:
            return datetime.datetime.now() # TODO last modified time of object in there?
        else:
            return datetime.datetime.fromtimestamp(os.stat(self.get_abs_path()).st_mtime)

    @property
    def is_collection(self):
        """Return True if this resource is a directory (collection in WebDAV parlance)."""
        path = '/'.join(self.path)
        # log.info(f"is_collection {self.path}")

        if path in [self.ROOT_FOLDER, self.MY_CATS_FOLDER, self.MARKUP_SUBMIT_FOLDER]:
            return True

        return False
        # return os.path.isdir(self.get_abs_path())

    @property
    def is_object(self):
        """Return True if this resource is a file (resource in WebDAV parlance)."""
        path = '/'.join(self.path)
        log.info(f"is_object {path}")

        if self.is_collection:
            return False

        # TODO test catalog pdf
        return True
        #return os.path.isfile(self.get_abs_path())

    @property
    def exists(self):
        """Return True if this resource exists."""
        path = '/'.join(self.path)
        log.info(f"exists {path}")

        if self.is_collection:
            return True

        # TODO test catalog pdf
        return os.path.exists(self.get_abs_path())

    # def write(self, content, temp_file=None, range_start=None):
    #     raise NotImplementedError

    # def read(self):
    #     raise NotImplementedError

    # def delete(self):
    #     """Delete the resource, recursive is implied."""
    #     if self.is_collection:
    #         for child in self.get_children():
    #             child.delete()
    #         os.rmdir(self.get_abs_path())
    #     elif self.is_object:
    #         os.remove(self.get_abs_path())

    # def create_collection(self):
    #     """Create a directory in the location of this resource."""
    #     os.mkdir(self.get_abs_path())

    # def copy_object(self, destination, depth=0):
    #     shutil.copy(self.get_abs_path(), destination.get_abs_path())

    # def move_object(self, destination):
    #     os.rename(self.get_abs_path(), destination.get_abs_path())

    # def read(self):
    #     return open(self.get_abs_path(), 'rb')

    # def write(self, request, temp_file=None, range_start=None):
    #     if temp_file:
    #         # move temp file (e.g., coming from nginx)
    #         shutil.move(temp_file, self.get_abs_path())
    #     elif range_start == None:
    #         # open binary file and write to disk
    #         with open(self.get_abs_path(), 'wb') as dst:
    #             shutil.copyfileobj(request, dst)
    #     else:
    #         # open binary file and write to disk
    #         with open(self.get_abs_path(), 'r+b') as dst:
    #             dst.seek(range_start)
    #             shutil.copyfileobj(request, dst)
