"""
Objetos de prueba mínimos.

Deliberadamente sin biblioteca de factorías: los modelos del primer corte son
pocos y crear una cuenta son tres líneas. Una dependencia más se justifica
cuando el armado empiece a repetirse de verdad, no antes.
"""

import json

from django.contrib.auth import get_user_model

from apps.credentials.models import Credential, CredentialStatus, GoogleProject, Module
from apps.credentials.services import _assign_to_module
from apps.domains.models import AccessState, Domain, PropertyType

#: Clave de cuenta de servicio con la forma exacta que entrega Google, pero sin
#: material real: el bloque PEM es un texto inventado. Sirve para ejercitar la
#: validación estructural, que es lo único que se puede probar sin salir a la red.
TEST_KEY = {
    'type': 'service_account',
    'project_id': 'proyecto-de-prueba-1',
    'private_key_id': '0123456789abcdef0123456789abcdef01234567',
    'private_key': '-----BEGIN PRIVATE KEY-----\nMIIsinValorReal\n-----END PRIVATE KEY-----\n',
    'client_email': 'relay@proyecto-de-prueba-1.iam.gserviceaccount.com',
    'client_id': '100000000000000000001',
    'token_uri': 'https://oauth2.googleapis.com/token',
}


def key_json(**overrides) -> bytes:
    data = {**TEST_KEY, **overrides}
    return json.dumps(data).encode()


def create_account(email='titular@ejemplo.test', password='contraseña-de-prueba', **extra):
    return get_user_model().objects.create_user(email=email, password=password, **extra)


def create_credential(
    account,
    *,
    status=CredentialStatus.VERIFIED,
    assign=True,
    properties=(),
    error='',
    checked_at=None,
) -> Credential:
    """
    Credencial en el estado que pida la prueba.

    `properties`, `error` y `checked_at` existen porque la pantalla de
    configuración no se ordena por el estado a secas: una clave que funciona
    pero no está autorizada, una verificada que alcanza tres propiedades y una
    que falló por un corte de red son tres pantallas distintas.
    """
    from apps.credentials.crypto import encrypt

    project, _ = GoogleProject.objects.get_or_create(
        account=account, project_id=TEST_KEY['project_id']
    )
    credential = Credential.objects.create(
        account=account,
        google_project=project,
        client_email=TEST_KEY['client_email'],
        encrypted_key=encrypt(json.dumps(TEST_KEY)),
        key_fingerprint='huella-de-prueba',
        private_key_id=TEST_KEY['private_key_id'],
        status=status,
        accessible_properties=list(properties),
        last_error_code=error,
        last_checked_at=checked_at,
    )
    if assign:
        _assign_to_module(account, credential, Module.SEARCH_CONSOLE)
    return credential


def create_domain(account, hostname='ejemplo.test', **extra) -> Domain:
    defaults = {
        'property_type': PropertyType.DOMAIN,
        'property_uri': f'sc-domain:{hostname}',
        'access_state': AccessState.OPERATIONAL,
        'daily_inspection_budget': 1000,
        'manual_reserve': 100,
    }
    return Domain.objects.create(account=account, hostname=hostname, **{**defaults, **extra})
