#!/usr/bin/python3
# Copyright 2020, Alexis de Lattre <alexis.delattre@akretion.com>
# Published under the BSD licence
# REST webservice to generated Factur-X invoice
# Sample client request:
#   curl -X POST -F 'pdf=@/home/alexis/invoice_test.pdf'
#        -F 'xml=@/home/alexis/factur-x.xml' -o result_facturx.pdf
#        http://localhost:5000/generate_facturx

from flask import Flask, request, send_file
from tempfile import NamedTemporaryFile
from facturx import generate_facturx_from_file
from facturx.facturx import logger as fxlogger
from optparse import OptionParser
import logging
from logging.handlers import RotatingFileHandler

MAX_ATTACHMENTS = 3  # TODO make it a cmd line option
app = Flask(__name__)


@app.route('/generate_facturx', methods=['POST'])
def generate_facturx():
    app.logger.debug('request.files=%s', request.files)
    attachments = {}
    for i in range(MAX_ATTACHMENTS):
        attach_key = 'attachment%d' % (i + 1)
        if request.files.get(attach_key):
            with NamedTemporaryFile(prefix='fx-api-attach-') as attach_file:
                request.files[attach_key].save(attach_file.name)
                attach_file.seek(0)
                attachments[request.files[attach_key].filename] = {
                    'filedata': attach_file.read(),
                    }
                attach_file.close()

    with NamedTemporaryFile(prefix='fx-api-xml-', suffix='.xml') as xml_file:
        request.files['xml'].save(xml_file.name)
        app.logger.debug('xml_file.name=%s', xml_file.name)
        xml_file.seek(0)
        xml_byte = xml_file.read()
        xml_file.close()
    res = ''
    with NamedTemporaryFile(prefix='fx-api-pdf-', suffix='.pdf') as pdf_file:
        with NamedTemporaryFile(
                prefix='fx-api-outpdf-', suffix='.pdf') as output_pdf_file:
            request.files['pdf'].save(pdf_file.name)
            app.logger.debug('pdf_file.name=%s', pdf_file.name)
            app.logger.debug('output_pdf_file.name=%s', output_pdf_file.name)
            app.logger.debug('attachments keys=%s', attachments.keys())
            generate_facturx_from_file(
                pdf_file, xml_byte, output_pdf_file=output_pdf_file.name,
                attachments=attachments)
            output_pdf_file.seek(0)
            res = send_file(output_pdf_file.name, as_attachment=True)
            app.logger.info(
                'Factur-X invoice successfully returned by webservice')
            output_pdf_file.close()
        pdf_file.close()
    return res


if __name__ == '__main__':
    usage = "Usage: facturx_webservice.py [options]"
    epilog = "Script written by Alexis de Lattre. "\
        "Published under the BSD licence."
    description = "This is a Flask application that exposes a REST "\
        "webservice to generate a Factur-X invoice from a PDF file and an "\
        "XML file."
    options_def = [
        {'names': ('-s', '--host'), 'dest': 'host', 'type': 'string',
         'action': 'store', 'default': '127.0.0.1',
         'help': "The hostname to listen on. Defaults to '127.0.0.1': "
         "the webservice will only accept connexions from localhost. Use "
         "'0.0.0.0' to have the webservice available from a remote host (but "
         "it is recommended to listen on localhost and use an HTTPS proxy to "
         "listen to remote connexions)."},
        {'names': ('-p', '--port'), 'dest': 'port', 'type': 'int',
         'action': 'store', 'default': 5000,
         'help': "Port on which the webservice listens. You can select "
         "any port between 1024 and 65535. Default port is 5000."},
        {'names': ('-d', '--debug'), 'dest': 'debug',
         'action': 'store_true', 'default': False,
         'help': "Enable debug mode."},
        {'names': ('-l', '--logfile'), 'dest': 'logfile', 'type': 'string',
         'action': 'store', 'default': False,
         'help': "Logs to a file instead of stdout."},
        {'names': ('-n', '--loglevel'), 'dest': 'loglevel', 'type': 'string',
         'action': 'store', 'default': 'info',
         'help': "Log level. Possible values: critical, error, warning, "
         "info (default), debug."},
    ]
    parser = OptionParser(usage=usage, epilog=epilog, description=description)
    for option in options_def:
        param = option['names']
        del option['names']
        parser.add_option(*param, **option)
    options, arguments = parser.parse_args()
    if options.logfile:
        formatter = logging.Formatter(
            "[%(asctime)s] %(levelname)s %(message)s")
        handler = RotatingFileHandler(options.logfile)
        if options.loglevel == 'debug':
            level = logging.DEBUG
        elif options.loglevel == 'critical':
            level = logging.CRITICAL
        elif options.loglevel == 'warning':
            level = logging.WARNING
        elif options.loglevel == 'error':
            level = logging.ERROR
        else:
            level = logging.INFO
        handler.setLevel(level)
        handler.setFormatter(formatter)
        fxlogger.setLevel(level)
        fxlogger.addHandler(handler)
        app.logger.addHandler(handler)
        app.logger.info('Start webservice to generate Factur-X invoices')
    app.run(debug=options.debug, port=options.port, host=options.host)
