# w.c.s. - web application for online forms
# Copyright (C) 2005-2010  Entr'ouvert
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.

import json
import hashlib
import urllib
import base64

from django.utils.encoding import force_text
from django.utils.six.moves.urllib import parse as urlparse

from .qommon import get_logger
from .qommon.misc import http_get_page, json_loads, http_post_request, urlopen
from quixote import get_publisher, get_request, get_response, redirect, get_session
from quixote.directory import Directory
from quixote.html import TemplateIO, htmltext

from wcs.api_utils import get_secret_and_orig, sign_url


def has_portfolio():
    return get_publisher().get_site_option('fargo_url') is not None


def fargo_url(url):
    fargo_url = get_publisher().get_site_option('fargo_url')
    url = urlparse.urljoin(fargo_url, url)
    secret, orig = get_secret_and_orig(url)
    if '?' in url:
        url += '&orig=%s' % orig
    else:
        url += '?orig=%s' % orig
    return sign_url(url, secret)


def fargo_get(url):
    url = fargo_url(url)
    response, status, data, auth_header = http_get_page(url)
    if status == 200:
        return json_loads(data)
    return {'err': 1}


def fargo_post_json(url, payload):
    url = fargo_url(url)
    headers = {'Content-Type': 'application/json'}
    response, status, response_payload, auth_header = http_post_request(
        url, json.dumps(payload), headers=headers)
    return status, json_loads(response_payload)


# Allow doing a signed POST in an afterjob, as fargo_url() does not work if no request is in
# context; so we do it in the constructor.
class fargo_post_json_async(object):
    def __init__(self, url, payload):
        self.url = fargo_url(url)
        self.payload = payload

    def __call__(self):
        headers = {'Content-Type': 'application/json'}
        response, status, response_payload, auth_header = http_post_request(
            self.url, json.dumps(self.payload), headers=headers)
        return status, json_loads(response_payload)


def sha256_of_upload(upload):
    return hashlib.sha256(upload.get_content()).hexdigest()


def push_document(user, filename, stream):
    if not user:
        return
    charset = get_publisher().site_charset
    payload = {}
    if user.name_identifiers:
        payload['user_nameid'] = force_text(user.name_identifiers[0], 'ascii')
    elif user.email:
        payload['user_email'] = force_text(user.email, 'ascii')
    payload['origin'] = urlparse.urlparse(get_publisher().get_frontoffice_url()).netloc
    payload['file_name'] = force_text(filename, charset)
    stream.seek(0)
    payload['file_b64_content'] = force_text(base64.b64encode(stream.read()))
    async_post = fargo_post_json_async('/api/documents/push/', payload)

    def afterjob(job):
        status = 0
        status, resp = async_post()
        if status == 200:
            get_logger().info('file %r pushed to portfolio of %r',
                              filename, user.display_name)
        else:
            get_logger().error('file %r failed to be pushed to portfolio of %r',
                               filename, user.display_name)

    if get_response():
        get_response().add_after_job(
            N_('Sending file %(filename)s in portfolio of %(user_name)s') % {
                'filename': filename,
                'user_name': user.display_name
            }, afterjob)
    else:
        afterjob(None)


class FargoDirectory(Directory):
    _q_exports = ['pick']

    @property
    def fargo_url(self):
        return get_publisher().get_site_option('fargo_url')

    def pick(self):
        request = get_request()
        if 'url' in request.form:
            # Download file
            # FIXME: handle error cases
            url = request.form['url']
            document = urlopen(request.form['url']).read()
            scheme, netloc, path, qs, frag = urlparse.urlsplit(url)
            path = map(None, path.split('/'))
            name = urllib.unquote(path[-1])
            from .qommon.form import PicklableUpload
            download = PicklableUpload(name, content_type='application/pdf')
            download.__setstate__({
                'data': document,
            })
            tempfile = get_session().add_tempfile(download)
            return self.set_token(tempfile.get('token'), name)
        else:
            # Display file picker
            frontoffice_url = get_publisher().get_frontoffice_url()
            self_url = frontoffice_url
            self_url += '/fargo/pick'
            return redirect('%spick?pick=%s' % (self.fargo_url, urllib.quote(self_url)))

    def set_token(self, token, title):
        get_response().add_javascript(['jquery.js'])
        get_response().page_template_key = 'iframe'
        r = TemplateIO(html=True)
        r += htmltext('<html><body>')
        r += htmltext('<script>window.top.document.fargo_set_token(%s, %s);</script>' % (
            json.dumps(token), json.dumps(title)))
        r += htmltext('</body></html>')
        return r.getvalue()
