from django.utils.translation import gettext_lazy as _
from drf_spectacular.extensions import OpenApiAuthenticationExtension
from .. import get_setting


class PasetoAuthenticationScheme(OpenApiAuthenticationExtension):
    target_class = 'encipher.authentication.PasetoAuthentication'
    name = 'PasetoAuth'

    def get_security_definition(self, auto_schema):
        return {
            'type': 'apiKey',
            'in': 'header',
            'name': 'Authorization',
            'description': base_description
            % {
                'method': get_setting('AUTH_METHOD'),
                'further_intro': intro_signed_key,
                'further_description': '',
                'user_claims': user_claims,
                'verification': verification_keys_signed,
            },
        }


class PasetoAutoAuthenticationScheme(OpenApiAuthenticationExtension):
    target_class = 'encipher.authentication.PasetoAutoAuthentication'
    name = 'PasetoAutoAuth'

    def get_security_definition(self, auto_schema):
        return {
            'type': 'apiKey',
            'in': 'header',
            'name': 'Authorization',
            'description': base_description
            % {
                'method': get_setting('PINNED_AUTH_METHOD'),
                'further_intro': intro_provided_key,
                'user_claims': user_claims,
                'verification': verification_keys_pinned_key,
            },
        }


base_description = _("""
Signed Paseto Token in authorization header - `Authorization %(method)s <signed-token>`. 

**A new token must be created signed for every http request!**

API Client must use Paseto v2 or v4 tokens, which are signed with an Ed25519 key. The API Server
must have an Encryption Key record assigned to the authenticating user. %(further_intro)s

%(further_description)s

### Generating Paseto Tokens

Paseto tokens are supported in various languages.

* Python - [pyseto](https://github.com/dajiaji/pyseto)
* C# - [paseto-dotnet](https://github.com/daviddesmet/paseto-dotnet)
* Go - [go-paseto](https://github.com/aidantwoods/go-paseto)
* Java - [jpaseto](https://github.com/paseto-toolkit/jpaseto)
* PHP - [paseto](https://github.com/paragonie/paseto)

## Token Payload

#### Verification Data
%(verification)s

%(user_claims)s
""")


user_claims = _("""
Token data must include one or more of the following keys to lookup the user 
(in the order of preference)

#### User Claims (one or more required)
| Key        | Description                 |
|------------|-----------------------------|
| `cid`      | Canonical ID of User record |
| `email`    | User's email address        |
| `username` | User's username / nickname  | 
""")


verification_keys_signed = _("""
| Key      | Description                                    |
|----------|------------------------------------------------|
| `time`   | UTC timestamp of date when token was generated |
| `nonce`  | Cryptographically secure random secret to avoid replay attacks |
""")


verification_keys_pinned_key = _("""
| Key      | Description                                  |
|----------|----------------------------------------------|
| `time`   | UTC timestamp of date when token was generated |
| `nonce`  | Cryptographically secure random secret to avoid replay attacks |
""")

intro_signed_key = _("""
This is the preferred method of authentication for machine-to-machine API communications, and
CLI access to API.
""")

intro_provided_key = _("""
Creating a new Encryption Public Key for a user from a pre-generated "pinned" EncryptionKey
is at times convenient, especially for registering a new client. 

_Use this method sparingly! IE registering new Encryption Keys in machine-to-machine applications._

This method can only be used for registering the first Public Key. After the initial registration,
new Public Keys should be created by tokens signed by Public Key specifically for that client.
""")


__all__ = (
    'PasetoAuthenticationScheme',
    'PasetoAutoAuthenticationScheme',
)
