# Copyright © The Debusine Developers
# See the AUTHORS file at the top-level directory of this distribution
#
# This file is part of Debusine. It is subject to the license terms
# in the LICENSE file found in the top-level directory of this
# distribution. No part of Debusine, including this file, may be copied,
# modified, propagated, or distributed except according to the terms
# contained in the LICENSE file.
"""Tests for rest framework extensions."""

from typing import override

from django.http import HttpRequest
from rest_framework.request import Request
from rest_framework.views import APIView

from debusine.server.views.rest import (
    IsGet,
    IsTokenAuthenticated,
    IsUserTokenAuthenticated,
    IsWorkRequestTokenAuthenticated,
    IsWorkerTokenAuthenticated,
)
from debusine.test.django import TestCase


class IsGetTests(TestCase):
    """Tests for IsGet."""

    @override
    def setUp(self) -> None:
        super().setUp()
        self.is_get = IsGet()
        self.http_request = Request(HttpRequest())

    def test_request_is_get(self) -> None:
        """Request method is GET. Return True."""
        self.http_request.method = "GET"

        self.assertTrue(
            self.is_get.has_permission(self.http_request, APIView())
        )

    def test_request_is_post(self) -> None:
        """Request method is POST. Return False."""
        self.http_request.method = "POST"

        self.assertFalse(
            self.is_get.has_permission(self.http_request, APIView())
        )


class IsTokenAuthenticatedTests(TestCase):
    """Tests for IsTokenAuthenticated."""

    @override
    def setUp(self) -> None:
        super().setUp()
        self.is_token_authenticated = IsTokenAuthenticated()
        self.request = Request(HttpRequest())

    def test_request_with_valid_token_worker_yes_permission(self) -> None:
        """IsTokenAuthenticated.has_permission() return True: valid token."""
        self.request.auth = self.playground.create_worker_token()
        self.assertTrue(
            self.is_token_authenticated.has_permission(self.request, APIView())
        )

    def test_request_with_non_existing_token_no_permission(self) -> None:
        """IsTokenAuthenticated.has_permission() return False: invalid token."""
        self.request.auth = None
        self.assertFalse(
            self.is_token_authenticated.has_permission(self.request, APIView())
        )

    def test_request_with_disabled_token_no_permission(self) -> None:
        """
        IsTokenAuthenticated.has_permission() return False.

        The token is disabled.
        """
        self.request.auth = self.playground.create_worker_token(enabled=False)
        self.assertFalse(
            self.is_token_authenticated.has_permission(self.request, APIView())
        )


class IsUserTokenAuthenticatedTests(TestCase):
    """Tests for IsUserTokenAuthenticated class."""

    @override
    def setUp(self) -> None:
        super().setUp()
        self.permission = IsUserTokenAuthenticated()
        self.request = Request(HttpRequest())

    def test_request_disabled_token(self) -> None:
        """Request with a Token header that is disabled: permission denied."""
        self.request.auth = self.playground.create_user_token(enabled=False)
        self.assertFalse(self.request.auth.enabled)
        self.assertFalse(
            self.permission.has_permission(self.request, APIView())
        )

    def test_request_non_existing_token(self) -> None:
        """Request without a token."""
        self.request.auth = None
        self.assertFalse(
            self.permission.has_permission(self.request, APIView())
        )

    def test_request_worker_token(self) -> None:
        """Request with a Worker Token: permission denied."""
        self.request.auth = self.playground.create_worker_token()
        self.assertFalse(
            self.permission.has_permission(self.request, APIView())
        )

    def test_request_worker_activation_token(self) -> None:
        """Request with a Worker Activation Token: permission denied."""
        self.request.auth = self.playground.create_worker_activation_token()
        self.assertFalse(
            self.permission.has_permission(self.request, APIView())
        )

    def test_request_enabled_token_with_user(self) -> None:
        """Request with a Token that does have a user: permission granted.."""
        self.request.auth = self.playground.create_user_token()
        self.assertTrue(self.permission.has_permission(self.request, APIView()))

    def test_request_work_request_token(self) -> None:
        """Request with a Work Request scoped Token: permission denied."""
        self.request.auth = self.playground.create_work_request_token()
        self.assertFalse(
            self.permission.has_permission(self.request, APIView())
        )


class IsWorkerTokenAuthenticatedTests(TestCase):
    """Tests for IsWorkerTokenAuthenticated."""

    @override
    def setUp(self) -> None:
        super().setUp()
        self.permission = IsWorkerTokenAuthenticated()
        self.request = Request(HttpRequest())

    def test_request_with_valid_token_worker_yes_permission(self) -> None:
        """IsWorkerTokenAuthenticated accepts valid token."""
        self.request.auth = self.playground.create_worker_token()
        self.assertTrue(self.permission.has_permission(self.request, APIView()))

    def test_request_with_non_existing_token_no_permission(self) -> None:
        """
        IsWorkerTokenAuthenticated.has_permission() return False.

        request.auth is None.
        """
        self.request.auth = None
        self.assertFalse(
            self.permission.has_permission(self.request, APIView())
        )

    def test_request_with_user_token_no_permission(self) -> None:
        """IsWorkerTokenAuthenticated rejects a user token."""
        self.request.auth = self.playground.create_user_token()
        self.assertFalse(
            self.permission.has_permission(self.request, APIView())
        )

    def test_request_work_request_token(self) -> None:
        """IsWorkerTokenAuthenticated rejects a work request scoped token."""
        self.request.auth = self.playground.create_work_request_token()
        self.assertFalse(
            self.permission.has_permission(self.request, APIView())
        )

    def test_request_worker_activation_token(self) -> None:
        """IsWorkerTokenAuthenticated rejects a worker activation token."""
        self.request.auth = self.playground.create_worker_activation_token()
        self.assertFalse(
            self.permission.has_permission(self.request, APIView())
        )


class IsWorkRequestTokenAuthenticatedTests(TestCase):
    """Tests for IsWorkRequestTokenAuthenticated."""

    @override
    def setUp(self) -> None:
        super().setUp()
        self.permission = IsWorkRequestTokenAuthenticated()
        self.request = Request(HttpRequest())

    def test_has_permission_valid_token(self) -> None:
        """has_permission() accepts a valid token."""
        self.request.auth = self.playground.create_work_request_token()
        self.assertTrue(self.permission.has_permission(self.request, APIView()))

    def test_has_permission_no_token(self) -> None:
        """has_permission() rejects an unauthenticated request."""
        self.request.auth = None
        self.assertFalse(
            self.permission.has_permission(self.request, APIView())
        )

    def test_has_permission_worker_token(self) -> None:
        """has_permission() rejects a non-scoped worker token."""
        self.request.auth = self.playground.create_worker_token()
        self.assertFalse(
            self.permission.has_permission(self.request, APIView())
        )

    def test_has_permission_user_token(self) -> None:
        """has_permission() rejects a user token."""
        self.request.auth = self.playground.create_user_token()
        self.assertFalse(
            self.permission.has_permission(self.request, APIView())
        )

    def test_has_permission_worker_activation_token(self) -> None:
        """has_permission() rejects a worker activation token."""
        self.request.auth = self.playground.create_worker_activation_token()
        self.assertFalse(
            self.permission.has_permission(self.request, APIView())
        )
