# Copyright 2011 OpenStack Foundation
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import webob.exc

from oslo.utils import strutils

from trove.common import exception
from trove.common import pagination
from trove.common import wsgi
from trove.common.utils import correct_id_with_req
from trove.extensions.mysql.common import populate_validated_databases
from trove.extensions.mysql.common import populate_users
from trove.extensions.mysql.common import unquote_user_host
from trove.extensions.mysql import models
from trove.extensions.mysql import views
from trove.guestagent.db import models as guest_models
from trove.openstack.common import log as logging
from trove.common.i18n import _
import trove.common.apischema as apischema


LOG = logging.getLogger(__name__)


class RootController(wsgi.Controller):
    """Controller for instance functionality."""

    def index(self, req, tenant_id, instance_id):
        """Returns True if root is enabled for the given instance;
                    False otherwise.
        """
        LOG.info(_("Getting root enabled for instance '%s'") % instance_id)
        LOG.info(_("req : '%s'\n\n") % req)
        context = req.environ[wsgi.CONTEXT_KEY]
        is_root_enabled = models.Root.load(context, instance_id)
        return wsgi.Result(views.RootEnabledView(is_root_enabled).data(), 200)

    def create(self, req, tenant_id, instance_id):
        """Enable the root user for the db instance."""
        LOG.info(_("Enabling root for instance '%s'") % instance_id)
        LOG.info(_("req : '%s'\n\n") % req)
        context = req.environ[wsgi.CONTEXT_KEY]
        user_name = context.user
        root = models.Root.create(context, instance_id, user_name)
        return wsgi.Result(views.RootCreatedView(root).data(), 200)


class UserController(wsgi.Controller):
    """Controller for instance functionality."""
    schemas = apischema.user

    @classmethod
    def get_schema(cls, action, body):
        action_schema = super(UserController, cls).get_schema(action, body)
        if 'update_all' == action:
            update_type = body.keys()[0]
            action_schema = action_schema.get(update_type, {})
        return action_schema

    def index(self, req, tenant_id, instance_id):
        """Return all users."""
        LOG.info(_("Listing users for instance '%s'") % instance_id)
        LOG.info(_("req : '%s'\n\n") % req)
        context = req.environ[wsgi.CONTEXT_KEY]
        users, next_marker = models.Users.load(context, instance_id)
        view = views.UsersView(users)
        paged = pagination.SimplePaginatedDataView(req.url, 'users', view,
                                                   next_marker)
        return wsgi.Result(paged.data(), 200)

    def create(self, req, body, tenant_id, instance_id):
        """Creates a set of users."""
        LOG.info(_("Creating users for instance '%s'") % instance_id)
        LOG.info(_("req : '%s'\n\n") % strutils.mask_password(req))
        LOG.info(_("body : '%s'\n\n") % strutils.mask_password(body))
        context = req.environ[wsgi.CONTEXT_KEY]
        users = body['users']
        try:
            model_users = populate_users(users)
            models.User.create(context, instance_id, model_users)
        except (ValueError, AttributeError) as e:
            raise exception.BadRequest(msg=str(e))
        return wsgi.Result(None, 202)

    def delete(self, req, tenant_id, instance_id, id):
        LOG.info(_("Deleting user for instance '%s'") % instance_id)
        LOG.info(_("req : '%s'\n\n") % req)
        context = req.environ[wsgi.CONTEXT_KEY]
        id = correct_id_with_req(id, req)
        username, host = unquote_user_host(id)
        user = None
        try:
            user = guest_models.MySQLUser()
            user.name = username
            user.host = host
            found_user = models.User.load(context, instance_id, username,
                                          host)
            if not found_user:
                user = None
        except (ValueError, AttributeError) as e:
            raise exception.BadRequest(msg=str(e))
        if not user:
            raise exception.UserNotFound(uuid=id)
        models.User.delete(context, instance_id, user.serialize())
        return wsgi.Result(None, 202)

    def show(self, req, tenant_id, instance_id, id):
        """Return a single user."""
        LOG.info(_("Showing a user for instance '%s'") % instance_id)
        LOG.info(_("req : '%s'\n\n") % req)
        context = req.environ[wsgi.CONTEXT_KEY]
        id = correct_id_with_req(id, req)
        username, host = unquote_user_host(id)
        user = None
        try:
            user = models.User.load(context, instance_id, username, host)
        except (ValueError, AttributeError) as e:
            raise exception.BadRequest(msg=str(e))
        if not user:
            raise exception.UserNotFound(uuid=id)
        view = views.UserView(user)
        return wsgi.Result(view.data(), 200)

    def update(self, req, body, tenant_id, instance_id, id):
        """Change attributes for one user."""
        LOG.info(_("Updating user attributes for instance '%s'") % instance_id)
        LOG.info(_("req : '%s'\n\n") % strutils.mask_password(req))
        context = req.environ[wsgi.CONTEXT_KEY]
        id = correct_id_with_req(id, req)
        username, hostname = unquote_user_host(id)
        user = None
        user_attrs = body['user']
        try:
            user = models.User.load(context, instance_id, username, hostname)
        except (ValueError, AttributeError) as e:
            raise exception.BadRequest(msg=str(e))
        if not user:
            raise exception.UserNotFound(uuid=id)
        try:
            models.User.update_attributes(context, instance_id, username,
                                          hostname, user_attrs)
        except (ValueError, AttributeError) as e:
            raise exception.BadRequest(msg=str(e))
        return wsgi.Result(None, 202)

    def update_all(self, req, body, tenant_id, instance_id):
        """Change the password of one or more users."""
        LOG.info(_("Updating user passwords for instance '%s'") % instance_id)
        LOG.info(_("req : '%s'\n\n") % strutils.mask_password(req))
        context = req.environ[wsgi.CONTEXT_KEY]
        users = body['users']
        model_users = []
        for user in users:
            try:
                mu = guest_models.MySQLUser()
                mu.name = user['name']
                mu.host = user.get('host')
                mu.password = user['password']
                found_user = models.User.load(context, instance_id,
                                              mu.name, mu.host)
                if not found_user:
                    user_and_host = mu.name