# This file is part of Indico.
# Copyright (C) 2002 - 2021 CERN
#
# Indico is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see the
# LICENSE file for more details.

from flask import flash, request, session
from werkzeug.exceptions import Forbidden, NotFound

from indico.core.config import config
from indico.core.errors import NoReportError
from indico.legacy.pdfinterface.latex import AbstractsToPDF
from indico.modules.events.abstracts.controllers.base import RHAbstractBase, RHAbstractsBase
from indico.modules.events.abstracts.models.abstracts import AbstractState
from indico.modules.events.abstracts.operations import create_abstract, update_abstract
from indico.modules.events.abstracts.util import get_user_abstracts, make_abstract_form
from indico.modules.events.abstracts.views import WPDisplayAbstracts, WPDisplayCallForAbstracts
from indico.modules.events.util import get_field_values
from indico.util.i18n import _
from indico.web.flask.util import send_file, url_for
from indico.web.forms.base import FormDefaults
from indico.web.util import jsonify_data, jsonify_form, jsonify_template


class RHCallForAbstracts(RHAbstractsBase):
    """Show the main CFA page."""

    def _process(self):
        abstracts = get_user_abstracts(self.event, session.user) if session.user else []
        return WPDisplayCallForAbstracts.render_template('display/call_for_abstracts.html', self.event,
                                                         abstracts=abstracts)


class RHMyAbstractsExportPDF(RHAbstractsBase):
    """Export the list of the user's abstracts as PDF."""

    def _check_access(self):
        if not session.user:
            raise Forbidden
        RHAbstractsBase._check_access(self)

    def _process(self):
        if not config.LATEX_ENABLED:
            raise NotFound
        pdf = AbstractsToPDF(self.event, get_user_abstracts(self.event, session.user))
        return send_file('my-abstracts.pdf', pdf.generate(), 'application/pdf')


class RHSubmitAbstract(RHAbstractsBase):
    """Submit a new abstract."""

    ALLOW_LOCKED = True

    def _check_access(self):
        cfa = self.event.cfa
        if session.user and not cfa.is_open and not cfa.can_submit_abstracts(session.user):
            raise NoReportError.wrap_exc(Forbidden(_('The Call for Abstracts is closed. '
                                                     'Please contact the event organizer for further assistance.')))
        elif not session.user or not cfa.can_submit_abstracts(session.user):
            raise Forbidden
        RHAbstractsBase._check_access(self)

    def _process(self):
        abstract_form_class = make_abstract_form(self.event, session.user, management=self.management)
        form = abstract_form_class(event=self.event)
        if form.validate_on_submit():
            abstract = create_abstract(self.event, *get_field_values(form.data), send_notifications=True)
            flash(_("Your abstract '{}' has been successfully submitted. It is registered with the number "
                    '#{}. You will be notified by email with the submission details.')
                  .format(abstract.title, abstract.friendly_id), 'success')
            return jsonify_data(flash=False, redirect=url_for('.call_for_abstracts', self.event))
        return jsonify_template('events/abstracts/display/submission.html', event=self.event, form=form)


class RHSubmitInvitedAbstract(RHAbstractBase):
    USE_ABSTRACT_UUID = True

    def _check_access(self):
        RHAbstractBase._check_access(self)
        if self.abstract.state != AbstractState.invited:
            raise Forbidden

    def _check_abstract_protection(self):
        token = request.view_args['uuid']
        return self.abstract.uuid == token

    def _create_form(self):
        form_user = session.user or self.abstract.submitter
        abstract_form_cls = make_abstract_form(self.event, form_user)
        custom_field_values = {f'custom_{x.contribution_field_id}': x.data for x in self.abstract.field_values}
        form_defaults = FormDefaults(self.abstract, **custom_field_values)
        return abstract_form_cls(obj=form_defaults, event=self.event, abstract=self.abstract)

    def _process_GET(self):
        return WPDisplayAbstracts.render_template('invited_abstract.html', self.abstract.event, abstract=self.abstract,
                                                  form=self._create_form())

    def _process_POST(self):
        form = self._create_form()
        if form.validate_on_submit():
            fields, custom_fields = get_field_values(form.data)
            abstract_data = dict(fields, state=AbstractState.submitted, uuid=None)
            update_abstract(self.abstract, abstract_data, custom_fields)
            return jsonify_data(flash=False, redirect=url_for('.call_for_abstracts', self.event))
        return jsonify_form(form, form_header_kwargs={'action': url_for('.submit_invited_abstract',
                                                                        self.abstract.locator.token)})
