from __future__ import print_function
from apiclient.discovery import build
from apiclient.http import MediaFileUpload
from httplib2 import Http
from oauth2client import file, client, tools
import mimetypes
import os


class DriveService:
    def __init__(self, driver=None):
        if driver == None:
            SCOPES = 'https://www.googleapis.com/auth/drive.file'
            store = file.Storage('credentials.json')
            creds = store.get()
            if not creds or creds.invalid:
                flow = client.flow_from_clientsecrets(
                    'client_secret.json', SCOPES)
                creds = tools.run_flow(flow, store)
            drive_service = build('drive', 'v3', http=creds.authorize(Http()))
        else:
            drive_service = driver

        self.drive_service = drive_service

    def create_folder(self, name, parent_id=None):
        metadata = {
            'name': name,
            'mimeType': 'application/vnd.google-apps.folder',
            'parents': [parent_id]
        }

        folder = self.drive_service.files().create(
            body=metadata,
            fields='id'
        ).execute()

        return folder.get('id')

    def upload_file(self, name, filePath, folder_id):
        fileType = mimetypes.guess_type(filePath)[0]
        if fileType == None:
            raise NameError("Invalid type or missing suffix!")

        file_metadata = {
            'name': name + '.' + fileType.split('/')[-1],
            'parents': [folder_id]
        }
        media = MediaFileUpload(filePath, mimetype=fileType)

        file = self.drive_service.files().create(
            body=file_metadata,
            media_body=media,
            fields='id webViewLink'
        ).execute()

        return {
            'id': file.get('id'),
            'link': file.get('webViewLink')
        }

    def writer_permission(self, email, file_id):
        batch = self.drive_service.new_batch_http_request(
            callback=self.__callback)
        permission = {
            'type': 'user',
            'role': 'writer',
            'emailAddress': email
        }
        batch.add(self.drive_service.permissions().create(
            fileId=file_id,
            body=permission,
            fields='id',
        ))
        batch.execute()

        return True

    def anyone_permission(self, file_id):
        batch = self.drive_service.new_batch_http_request(
            callback=self.__callback)
        permission = {
            'type': 'anyone',
            'role': 'reader'
        }
        batch.add(self.drive_service.permissions().create(
            fileId=file_id,
            body=permission,
            fields='id',
        ))
        batch.execute()

        return {'link': 'https://drive.google.com/file/d/{0}/view?usp=sharing'.format(file_id)}

    def list_folders_by_name(self, name):
        return self.__list_items_by_name(name, "mimeType = 'application/vnd.google-apps.folder'")

    def list_files_by_name(self, name):
        return self.__list_items_by_name(name, "mimeType != 'application/vnd.google-apps.folder'")

    def list_files_from_folder_id(self, folder_id):
        itemsList = []

        page_token = None
        while True:
            response = self.drive_service.files().list(
                q="'" + folder_id + "' in parents",
                spaces='drive',
                fields='nextPageToken, files(id, name, modifiedTime, mimeType, size)',
                pageToken=page_token
            ).execute()

            for file in response.get('files', []):
                # Process change
                itemsList.append({
                    'id': file.get('id'),
                    'name': file.get('name'),
                    'modifiedTime': file.get('modifiedTime'),
                    'type': file.get('mimeType'),
                    'size': file.get('size')
                })
            page_token = response.get('nextPageToken', None)
            if page_token is None:
                break

        return itemsList

    def __list_items_by_name(self, name, extraQuery=None):
        if len(name.split(' ')) > 1:
            query = ''
            for nm in name.split(' '):
                query += 'name contains ' + nm + ' and '
            query = query[:-5]
        else:
            query = name

        if extraQuery != None:
            query += " and " + extraQuery

        itemsList = []

        page_token = None
        while True:
            response = self.drive_service.files().list(
                q=query,
                spaces='drive',
                fields='nextPageToken, files(id, name, modifiedTime, mimeType, size)',
                pageToken=page_token
            ).execute()

            for file in response.get('files', []):
                # Process change
                itemsList.append({
                    'id': file.get('id'),
                    'name': file.get('name'),
                    'modifiedTime': file.get('modifiedTime'),
                    'type': file.get('mimeType'),
                    'size': file.get('size')
                })
            page_token = response.get('nextPageToken', None)
            if page_token is None:
                break

        return itemsList

    def __callback(self, request_id, response, exception):
        if exception:
            # Handle error
            print(exception)
        else:
            pass


