# Copyright (c) 2012-2016 Seafile Ltd.
import logging

from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status
from django.utils.translation import ugettext as _

from seaserv import seafile_api
from pysearpc import SearpcError

from seahub.api2.authentication import TokenAuthentication
from seahub.api2.throttling import UserRateThrottle
from seahub.api2.utils import api_error
from seahub.utils.repo import is_repo_owner, add_encrypted_repo_secret_key_to_database
from seahub.base.models import RepoSecretKey
from seahub.views import check_folder_permission

from seahub.settings import ENABLE_RESET_ENCRYPTED_REPO_PASSWORD

logger = logging.getLogger(__name__)

class RepoSetPassword(APIView):

    authentication_classes = (TokenAuthentication, SessionAuthentication )
    permission_classes = (IsAuthenticated,)
    throttle_classes = (UserRateThrottle,)

    def post(self, request, repo_id):
        """ Check if repo password is correct.

        Permission checking:
        1. User can access current repo.
        """

        # argument check
        password = request.POST.get('password', None)
        if not password:
            error_msg = 'password invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        # resource check
        repo = seafile_api.get_repo(repo_id)
        if not repo:
            error_msg = 'Library %s not found.' % repo_id
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        if not repo.encrypted:
            error_msg = 'Library %s is not encrypted.' % repo_id
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        # permission check
        if not check_folder_permission(request, repo_id, '/'):
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        # check the password is correct
        try:
            seafile_api.set_passwd(repo_id, request.user.username, password)
        except SearpcError as e:
            if e.msg == 'Bad arguments':
                error_msg = 'Bad arguments'
                return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
            elif e.msg == 'Incorrect password':
                error_msg = _(u'Wrong password')
                return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
            elif e.msg == 'Internal server error':
                error_msg = _(u'Internal server error')
                return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
            else:
                error_msg = _(u'Decrypt library error')
                return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

        if ENABLE_RESET_ENCRYPTED_REPO_PASSWORD:
            add_encrypted_repo_secret_key_to_database(repo_id, password)

        return Response({'success': True})

    def put(self, request, repo_id):
        """ Change/Init repo password.

        Permission checking:
        1. repo owner
        """

        # argument check
        operation = request.POST.get('operation', 'change-password')
        operation = operation.lower()
        if operation not in ('change-password', 'reset-password', 'can-reset-password'):
            error_msg = 'operation invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        # resource check
        repo = seafile_api.get_repo(repo_id)
        if not repo:
            error_msg = 'Library %s not found.' % repo_id
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        if not repo.encrypted:
            error_msg = 'Library %s is not encrypted.' % repo_id
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        # permission check
        username = request.user.username
        if not is_repo_owner(request, repo_id, username):
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        if operation == 'change-password':

            old_password = request.POST.get('old_password', None)
            if not old_password:
                error_msg = 'old_password invalid.'
                return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

            new_password = request.POST.get('new_password', None)
            if not new_password:
                error_msg = 'new_password invalid.'
                return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

            try:
                seafile_api.change_repo_passwd(repo_id, old_password, new_password, username)
            except Exception as e:
                if e.msg == 'Incorrect password':
                    error_msg = _(u'Wrong old password')
                    return api_error(status.HTTP_403_FORBIDDEN, error_msg)
                else:
                    logger.error(e)
                    error_msg = 'Internal Server Error'
                    return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

            if ENABLE_RESET_ENCRYPTED_REPO_PASSWORD:
                add_encrypted_repo_secret_key_to_database(repo_id, new_password)

        if operation == 'can-reset-password':
            if not ENABLE_RESET_ENCRYPTED_REPO_PASSWORD:
                error_msg = 'Feature disabled.'
                return api_error(status.HTTP_403_FORBIDDEN, error_msg)

            if not RepoSecretKey.objects.get_secret_key(repo_id):
                return Response({'allowed': False})
            else:
                return Response({'allowed': True})

        if operation == 'reset-password':

            if not ENABLE_RESET_ENCRYPTED_REPO_PASSWORD:
                error_msg = 'Feature disabled.'
                return api_error(status.HTTP_403_FORBIDDEN, error_msg)

            new_password = request.POST.get('new_password', None)
            if not new_password:
                error_msg = 'new_password invalid.'
                return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

            secret_key =  RepoSecretKey.objects.get_secret_key(repo_id)
            if not secret_key:
                error_msg = 'repo_id invalid.'
                return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

            try:
                seafile_api.reset_repo_passwd(repo_id, username, secret_key, new_password)
            except Exception as e:
                logger.error(e)
                error_msg = 'Internal Server Error'
                return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

        return Response({'success': True})
