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

import posixpath
from urllib.parse import urlsplit, urlunsplit

from flask import jsonify, request, session
from flask_pluginengine import render_plugin_template
from werkzeug.exceptions import BadRequest, NotFound

from indico.core.config import config
from indico.modules.events.management.controllers import RHManageEventBase
from indico.web.rh import RH
from indico.web.util import jsonify_template

from indico_ursh import _
from indico_ursh.util import is_configured, register_shortcut, request_short_url, strip_end
from indico_ursh.views import WPShortenURLPage


CUSTOM_SHORTCUT_ALPHABET = frozenset('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-')


class RHGetShortURL(RH):
    """Make a request to the URL shortening service"""

    @staticmethod
    def _resolve_full_url(original_url):
        if urlsplit(original_url).hostname:
            return original_url
        original_url = original_url.lstrip('/')
        return posixpath.join(config.BASE_URL, original_url)

    @staticmethod
    def _check_host(full_url):
        if urlsplit(full_url).hostname != urlsplit(config.BASE_URL).hostname:
            raise BadRequest('Invalid host for URL shortening service')

    def _process(self):
        original_url = request.json.get('original_url')
        full_url = self._resolve_full_url(original_url)
        self._check_host(full_url)
        short_url = request_short_url(full_url)
        return jsonify(url=short_url)


class RHShortURLPage(RH):
    """Provide a simple page where users can submit a URL to be shortened"""

    def _process(self):
        if not is_configured():
            raise NotFound('Plugin is not configured')
        return WPShortenURLPage.render_template('ursh_shortener_page.html')


class RHCustomShortURLPage(RHManageEventBase):
    """Provide a simple page, where users can submit a URL to be shortened"""

    def _make_absolute_url(self, url):
        return posixpath.join(config.BASE_URL, url[1:]) if url.startswith('/') else url

    def _get_error_msg(self, result):
        if result['status'] == 409:
            return _('Shortcut already exists')
        elif result['status'] == 400:
            return _('Malformed shortcut')
        return result['error'].get('description')

    def _process_args(self):
        from indico_ursh.plugin import UrshPlugin
        super()._process_args()
        api_host = urlsplit(UrshPlugin.settings.get('api_host'))
        self.ursh_host = strip_end(urlunsplit(api_host), api_host.path[1:]).rstrip('/') + '/'

    def _process_GET(self):
        original_url = self._make_absolute_url(request.args['original_url'])
        return WPShortenURLPage.render_template('ursh_custom_shortener_page.html',
                                                event=self.event,
                                                ursh_host=self.ursh_host,
                                                original_url=original_url,
                                                submitted=False,
                                                shortcut=None)

    def _process_POST(self):
        original_url = self._make_absolute_url(request.args['original_url'])
        shortcut = request.form['shortcut'].strip()

        if not (set(shortcut) <= CUSTOM_SHORTCUT_ALPHABET):
            raise BadRequest('Invalid shortcut')

        result = register_shortcut(original_url, shortcut, session.user)

        if result.get('error'):
            kwargs = {'success': False, 'msg': self._get_error_msg(result)}
        else:
            kwargs = {'success': True, 'shorturl': result['short_url']}

        return jsonify_template('ursh_custom_shortener_page.html', render_plugin_template,
                                event=self.event, ursh_host=self.ursh_host, shortcut=shortcut,
                                original_url=original_url, submitted=True, **kwargs)
