# -*- coding: utf-8; -*-
################################################################################
#
#  Rattail -- Retail Software Framework
#  Copyright © 2010-2020 Lance Edgar
#
#  This file is part of Rattail.
#
#  Rattail 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 3 of the License, or (at your option) any later
#  version.
#
#  Rattail 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
#  Rattail.  If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Various common views
"""

from __future__ import unicode_literals, absolute_import

import six

import rattail
from rattail.db import model
from rattail.batch import consume_batch_id
from rattail.mail import send_email
from rattail.util import OrderedDict
from rattail.files import resource_path

from pyramid import httpexceptions
from pyramid.response import Response

import tailbone
from tailbone import forms
from tailbone.forms.common import Feedback
from tailbone.db import Session
from tailbone.views import View
from tailbone.util import set_app_theme
from tailbone.config import global_help_url


class CommonView(View):
    """
    Base class for common views; override as needed.
    """
    project_title = "Tailbone"
    project_version = tailbone.__version__
    robots_txt_path = resource_path('tailbone.static:robots.txt')

    def home(self, mobile=False):
        """
        Home page view.
        """
        if not mobile and not self.request.user:
            if self.rattail_config.getbool('tailbone', 'login_is_home', default=True):
                raise self.redirect(self.request.route_url('login'))

        image_url = self.rattail_config.get(
            'tailbone', 'main_image_url',
            default=self.request.static_url('tailbone:static/img/home_logo.png'))

        use_buefy = self.get_use_buefy()
        context = {
            'image_url': image_url,
            'use_buefy': use_buefy,
            'help_url': global_help_url(self.rattail_config),
        }
        if use_buefy:
            context['index_title'] = self.rattail_config.node_title()

        if self.expose_quickie_search:
            context['quickie'] = self.get_quickie_context()

        return context

    def robots_txt(self):
        """
        Returns a basic 'robots.txt' response
        """
        with open(self.robots_txt_path, 'rt') as f:
            content = f.read()
        response = self.request.response
        if six.PY3:
            response.text = content
            response.content_type = 'text/plain'
        else:
            response.body = content
            response.content_type = b'text/plain'
        return response

    def mobile_home(self):
        """
        Home page view for mobile.
        """
        return self.home(mobile=True)

    def exception(self):
        """
        Generic exception view
        """
        return {'project_title': self.project_title}

    def about(self):
        """
        Generic view to show "about project" info page.
        """
        return {
            'project_title': self.project_title,
            'project_version': self.project_version,
            'packages': self.get_packages(),
            'use_buefy': self.get_use_buefy(),
        }

    def get_packages(self):
        """
        Should return the full set of packages which should be displayed on the
        'about' page.
        """
        return OrderedDict([
            ('rattail', rattail.__version__),
            ('Tailbone', tailbone.__version__),
        ])

    def change_theme(self):
        """
        Simple view which can change user's visible UI theme, then redirect
        user back to referring page.
        """
        theme = self.request.params.get('theme')
        if theme:
            try:
                set_app_theme(self.request, theme, session=Session())
            except Exception as error:
                msg = "Failed to set theme: {}: {}".format(error.__class__.__name__, error)
                self.request.session.flash(msg, 'error')
            else:
                self.request.session.flash("App theme has been changed to: {}".format(theme))
        return self.redirect(self.request.get_referrer())

    def change_db_engine(self):
        """
        Simple view which can change user's "current" database engine, of a
        given type, then redirect back to referring page.
        """
        engine_type = self.request.POST.get('engine_type')
        if engine_type:
            dbkey = self.request.POST.get('dbkey')
            if dbkey:
                self.request.session['tailbone.engines.{}.current'.format(engine_type)] = dbkey
                if self.rattail_config.getbool('tailbone', 'engines.flash_after_change', default=True):
                    self.request.session.flash("Switched '{}' database to: {}".format(engine_type, dbkey))
        return self.redirect(self.request.get_referrer())

    def feedback(self):
        """
        Generic view to handle the user feedback form.
        """
        schema = Feedback().bind(session=Session())
        form = forms.Form(schema=schema, request=self.request)
        if form.validate(newstyle=True):
            data = dict(form.validated)
            if data['user']:
                data['user'] = Session.query(model.User).get(data['user'])
                data['user_url'] = self.request.route_url('users.view', uuid=data['user'].uuid)
            data['client_ip'] = self.request.client_addr
            send_email(self.rattail_config, 'user_feedback', data=data)
            return {'ok': True}
        return {'error': "Form did not validate!"}

    def mobile_feedback(self):
        """
        Generic view to handle the user feedback form on mobile.
        """
        return self.feedback()

    def consume_batch_id(self):
        """
        Consume next batch ID from the PG sequence, and display via flash message.
        """
        batch_id = consume_batch_id(Session())
        self.request.session.flash("Batch ID has been consumed: {:08d}".format(batch_id))
        return self.redirect(self.request.get_referrer())

    def bogus_error(self):
        """
        A special view which simply raises an error, for the sake of testing
        uncaught exception handling.
        """
        raise Exception("Congratulations, you have triggered a bogus error.")

    @classmethod
    def defaults(cls, config):
        cls._defaults(config)

    @classmethod
    def _defaults(cls, config):
        rattail_config = config.registry.settings.get('rattail_config')
        legacy_mobile = cls.legacy_mobile_enabled(rattail_config)

        # auto-correct URLs which require trailing slash
        config.add_notfound_view(cls, attr='notfound', append_slash=True)

        # exception
        if rattail_config and rattail_config.production():
            config.add_exception_view(cls, attr='exception', renderer='/exception.mako')

        # permissions
        config.add_tailbone_permission_group('common', "(common)", overwrite=False)

        # home
        config.add_route('home', '/')
        config.add_view(cls, attr='home', route_name='home', renderer='/home.mako')
        if legacy_mobile:
            config.add_route('mobile.home', '/mobile/')
            config.add_view(cls, attr='mobile_home', route_name='mobile.home', renderer='/mobile/home.mako')

        # robots.txt
        config.add_route('robots.txt', '/robots.txt')
        config.add_view(cls, attr='robots_txt', route_name='robots.txt')

        # about
        config.add_route('about', '/about')
        config.add_view(cls, attr='about', route_name='about', renderer='/about.mako')
        if legacy_mobile:
            config.add_route('mobile.about', '/mobile/about')
            config.add_view(cls, attr='about', route_name='mobile.about', renderer='/mobile/about.mako')

        # change db engine
        config.add_tailbone_permission('common', 'common.change_db_engine',
                                       "Change which Database Engine is active (for user)")
        config.add_route('change_db_engine', '/change-db-engine', request_method='POST')
        config.add_view(cls, attr='change_db_engine', route_name='change_db_engine')

        # change theme
        config.add_tailbone_permission('common', 'common.change_app_theme',
                                       "Change global App Template Theme")
        config.add_route('change_theme', '/change-theme', request_method='POST')
        config.add_view(cls, attr='change_theme', route_name='change_theme')

        # feedback
        config.add_tailbone_permission('common', 'common.feedback',
                                       "Send user feedback (to admins) about the app")
        config.add_route('feedback', '/feedback', request_method='POST')
        config.add_view(cls, attr='feedback', route_name='feedback',
                        renderer='json', permission='common.feedback')
        if legacy_mobile:
            config.add_route('mobile.feedback', '/mobile/feedback', request_method='POST')
            config.add_view(cls, attr='mobile_feedback', route_name='mobile.feedback',
                            renderer='json', permission='common.feedback')

        # consume batch ID
        config.add_tailbone_permission('common', 'common.consume_batch_id',
                                       "Consume new Batch ID")
        config.add_route('consume_batch_id', '/consume-batch-id')
        config.add_view(cls, attr='consume_batch_id', route_name='consume_batch_id')

        # bogus error
        config.add_route('bogus_error', '/bogus-error')
        config.add_view(cls, attr='bogus_error', route_name='bogus_error', permission='errors.bogus')


def includeme(config):
    CommonView.defaults(config)
