import io
import os
import tempfile
from datetime import datetime

import requests
import validators
import webdav3.client as wc
from cookbook.models import Recipe, RecipeImport, SyncLog
from cookbook.provider.provider import Provider
from requests.auth import HTTPBasicAuth

from recipes.settings import DEBUG


class Nextcloud(Provider):

    @staticmethod
    def get_client(storage):
        options = {
            'webdav_hostname': storage.url,
            'webdav_login': storage.username,
            'webdav_password': storage.password,
            'webdav_root': '/remote.php/dav/files/' + storage.username
        }
        if storage.path != '':
            options['webdav_root'] = storage.path
        return wc.Client(options)

    @staticmethod
    def import_all(monitor):
        client = Nextcloud.get_client(monitor.storage)

        if DEBUG:
            print(f'TANDOOR_PROVIDER_DEBUG checking path  {monitor.path} with client {client}')

        files = client.list(monitor.path)

        if DEBUG:
            print(f'TANDOOR_PROVIDER_DEBUG file list  {files}')

        import_count = 0
        for file in files:
            if DEBUG:
                print(f'TANDOOR_PROVIDER_DEBUG importing file {file}')
            path = monitor.path + '/' + file
            if not Recipe.objects.filter(file_path__iexact=path, space=monitor.space).exists() and not RecipeImport.objects.filter(file_path=path, space=monitor.space).exists():
                name = os.path.splitext(file)[0]
                new_recipe = RecipeImport(
                    name=name,
                    file_path=path,
                    storage=monitor.storage,
                    space=monitor.space,
                )
                new_recipe.save()
                import_count += 1

        log_entry = SyncLog(
            status='SUCCESS',
            msg='Imported ' + str(import_count) + ' recipes',
            sync=monitor,
        )
        log_entry.save()

        monitor.last_checked = datetime.now()
        monitor.save()

        return True

    @staticmethod
    def create_share_link(recipe):
        url = recipe.storage.url + '/ocs/v2.php/apps/files_sharing/api/v1/shares?format=json'  # noqa: E501

        headers = {
            "OCS-APIRequest": "true",
            "Content-Type": "application/x-www-form-urlencoded"
        }

        data = {'path': recipe.file_path, 'shareType': 3}

        r = requests.post(url, headers=headers, auth=HTTPBasicAuth(recipe.storage.username, recipe.storage.password), data=data)

        response_json = r.json()

        return response_json['ocs']['data']['url']

    @staticmethod
    def get_share_link(recipe):
        url = recipe.storage.url + '/ocs/v2.php/apps/files_sharing/api/v1/shares?format=json&path=' + recipe.file_path  # noqa: E501

        headers = {
            "OCS-APIRequest": "true",
            "Content-Type": "application/json"
        }

        if validators.url(url, public=True):
            r = requests.get(
                url,
                headers=headers,
                auth=HTTPBasicAuth(
                    recipe.storage.username, recipe.storage.password
                )
            )

            response_json = r.json()
            for element in response_json['ocs']['data']:
                if element['share_type'] == '3':
                    return element['url']

            return Nextcloud.create_share_link(recipe)

    @staticmethod
    def get_file(recipe):
        client = Nextcloud.get_client(recipe.storage)

        tmp_file_path = tempfile.gettempdir() + '/' + recipe.name + '.pdf'

        client.download_file(
            remote_path=recipe.file_path,
            local_path=tmp_file_path
        )

        file = io.BytesIO(open(tmp_file_path, 'rb').read())
        os.remove(tmp_file_path)

        return file

    @staticmethod
    def rename_file(recipe, new_name):
        client = Nextcloud.get_client(recipe.storage)

        client.move(
            recipe.file_path,
            "%s/%s%s" % (
                os.path.dirname(recipe.file_path),
                new_name,
                os.path.splitext(recipe.file_path)[1]
            )
        )

        return True

    @staticmethod
    def delete_file(recipe):
        client = Nextcloud.get_client(recipe.storage)

        client.clean(recipe.file_path)

        return True
