import click
import requests
import json
import shutil
from pathlib import Path
from mimetypes import guess_extension


def get_rev(url, uuid):
    """Get the revision stamp."""

    rev = requests.get(url + "/" + uuid)
    handle_requests(rev, "Revision request")
    rev = json.loads(rev.content.decode('utf-8'))['_rev']

    return rev


def handle_requests(req, request_type):
    """Handle requests."""

    if not req.ok:
        raise click.ClickException(request_type + " request returned status " + str(req.status_code) + "\nCaused by: " + json.loads(req.content)['reason'])


#  ──────────────────────────────────────────────────────────────────────────
# adding

def add_file(file, djvu, attachment, url, uuid, rev):
    """Insert document file."""

    file = Path(file).expanduser().resolve()
    if file.exists():
        with click.open_file(file, 'rb') as file:
            if djvu:
                headers = {'content-type': 'image/vnd.djvu'}
            else:
                headers={'content-type': 'application/pdf'}

            insert = requests.put(url + "/" + uuid + "/" + attachment + "?rev=" + rev, data=file, headers=headers)
            handle_requests(insert, "Insert " + attachment + " file")

    else:
        raise click.ClickException("File for " + attachment + " doesn't exist!")


def add_files(url, uuid, file, corrections, annotated, supplemental, djvu, corrections_djvu, annotated_djvu, supplemental_djvu):
    """Insert attachment files."""
    # Should FIX this to handle the errors separately when trying to add the document and its files

    print(uuid, file, corrections, annotated, supplemental)

    if file != None:
        rev = get_rev(url, uuid)
        add_file(file, djvu, "document", url, uuid, rev)
        delete_file(file)

    if corrections != None:
        rev = get_rev(url, uuid)
        add_file(corrections, corrections_djvu, "corrections", url, uuid, rev)
        delete_file(corrections)

    if annotated != None:
        rev = get_rev(url, uuid)
        add_file(annotated, annotated_djvu, "annotated", url, uuid, rev)
        delete_file(annotated)

    if supplemental != None:
        rev = get_rev(url, uuid)
        add_file(supplemental, supplemental_djvu, "supplemental", url, uuid, rev)
        delete_file(supplemental)


def delete_file(file):
    """Conditional delete file"""

    file = Path(file).expanduser().resolve()
    if click.confirm("Are you sure you want to delete file: " + click.style(str(file), italic=True) + " after insertion?"):
        file.unlink(missing_ok=False)


def insert_document(url, uuid, doc, file, corrections, annotated, supplemental, djvu, corrections_djvu, annotated_djvu, supplemental_djvu):
    """Insert document."""

    click.echo(json.dumps(doc, indent=4))
    click.confirm("Are you sure you want to insert the above document?", abort=True)

    try:
        modify_document(url, uuid, doc, "Inserting")

    except:
        raise click.ClickException("Failed inserting!")

    
    # insert document files
    try:
        add_files(url, uuid, file, corrections, annotated, supplemental, djvu, corrections_djvu, annotated_djvu, supplemental_djvu)

    except:
        # # deleting the partial input - FIX
        # req = requests.post(ctx.obj['url'] + "/_purge", data=json.dumps({uuid: [rev]}), headers={"Content-Type": "application/json"}) # inserting returns a revision hash
        # fn.handle_requests(req, "Bad insertion")

        raise click.ClickException("Failed to upload attachment files!")


def modify_document(url, uuid, doc, modify_type):
    """Insert/modify/update document."""

    req = requests.put(url + "/" + uuid, data=json.dumps(doc), headers={"Accept": "application/json", "Accept": "application/json"}) # inserting returns a revision hash
    handle_requests(req, modify_type)


def document_exists(url, uuid):
    """Check if the document with the ID exists."""

    # requesting with id
    search_json = {"selector": {"_id": uuid}}
    content = search_document(url, search_json)


    # check if document exists
    doc = content['docs']
    if len(doc) > 0:
        return doc[0]

    else:
        # fail and abort if doesn't exist
        raise click.ClickException("Document not found!")


def delete_document(url, uuid):
    """Delete document."""

    rev = get_rev(url, uuid)
    req = requests.delete(url + "/" + uuid + "?rev=" + rev, headers={'Accept': 'application/json'})
    handle_requests(req, "Delete")


def search_document(url, search_json):
    """Search for document in database."""

    req = requests.post(url + "/_find", data=json.dumps(search_json), headers={'Content-Type': 'application/json'})
    handle_requests(req, "Search")

    return json.loads(req.content)


#  ──────────────────────────────────────────────────────────────────────────
# pulling

def download_file(url, file, uuid, cache):
    """Download file from database."""

    with requests.get(url, stream=True) as req:

        # handle errors
        handle_requests(req, "Download")


        # saving to cache
        dir_path = cache / Path(file)
        dir_path.mkdir(parents=True, exist_ok=True)
        file_path = dir_path / Path(uuid + guess_extension(req.headers['content-type']))


        # return if cached already
        if file_path.exists():
            return url, file_path


        else:
            # downloading with nice progress bar
            with click.open_file(file_path, 'wb') as open_file:
                chunks = req.iter_content(chunk_size=8192)

                with click.progressbar(chunks, label="File not found in locally, downloading") as bar:
                    for chunk in bar:
                        open_file.write(chunk)


            return url, file_path
