from types import SimpleNamespace
from rest_framework.exceptions import ValidationError

def required_query_param(request, name):
  value = request.query_params.get(name) or ''

  if not len(value): raise ValidationError({ name: ['Tento parametr je povinný.'] })

  return value

def required_body_param(request, name):
  value = request.data.get(name)

  if value is None: raise ValidationError({ name: ['Toto pole nesmí být prázdné.'] })

  return value

def optional_query_param(request, name, default = None):
  return request.query_params.get(name, default)

def optional_body_param(request, name, default = None):
  return request.data.get(name, default)

def required_query_params(request, *names):
  return [required_query_param(request, name) for name in names]

def required_body_params(request, *names):
  return [required_body_param(request, name)  for name in names]

def optional_query_params(request, *names):
  return [optional_query_param(request, name) for name in names]

def optional_body_params(request, *names):
  return [optional_body_param(request, name)  for name in names]

class Params(SimpleNamespace):
  def __getitem__(self, name):
    return getattr(self, name)

def extract_params(request, spec):
  if callable(spec): spec = spec()

  params      = Params()
  query, body = spec.get('query'), spec.get('body')

  if query:
    required, optional = query.get('required'), query.get('optional')

    if required:
      for name in required:
        setattr(params, name, required_query_param(request, name))
    if optional:
      for name in optional:
        setattr(params, name, optional_query_param(request, name))

  if body:
    required, optional = body.get('required'), body.get('optional')

    if required:
      for name in required:
        setattr(params, name, required_body_param(request, name))
    if optional:
      for name in optional:
        setattr(params, name, optional_body_param(request, name))

  return params

def with_params(spec):
  def decorator(view):
    def wrapper(self, request, *args, **kwargs):
      params = extract_params(request, spec)

      return view(self, request, params, *args, **kwargs)
    return wrapper
  return decorator

class WithParams:
  def params(self, request, spec = None):
    spec = spec or self.params_spec

    return extract_params(request, spec)
