#!/usr/bin/env python
"""Test classes for ACL-related testing."""

from typing import Optional

from grr_response_core.lib import rdfvalue
from grr_response_server import data_store
from grr_response_server.gui import api_call_context
from grr_response_server.gui.api_plugins import user as api_user
from grr_response_server.rdfvalues import objects as rdf_objects


def CreateUser(username):
  """Creates a user."""
  data_store.REL_DB.WriteGRRUser(username)


def CreateAdminUser(username):
  data_store.REL_DB.WriteGRRUser(
      username, user_type=rdf_objects.GRRUser.UserType.USER_TYPE_ADMIN)


def BuildClientApprovalRequest(
    client_id: Optional[str] = None,
    requestor_username: Optional[str] = None,
    reason: Optional[str] = None) -> rdf_objects.ApprovalRequest:
  return rdf_objects.ApprovalRequest(
      approval_type=rdf_objects.ApprovalRequest.ApprovalType
      .APPROVAL_TYPE_CLIENT,
      subject_id=client_id or "C.1234",
      requestor_username=requestor_username or "testuser",
      reason=reason or "foo/test1234",
      expiration_time=rdfvalue.RDFDatetime.Now() +
      rdfvalue.Duration.From(1, rdfvalue.DAYS))


class AclTestMixin(object):
  """Mixing providing ACL-related helper methods."""

  def CreateUser(self, username):
    return CreateUser(username)

  def CreateAdminUser(self, username):
    """Creates a user and makes it an admin."""
    return CreateAdminUser(username)

  def RequestClientApproval(self,
                            client_id,
                            reason="Running tests",
                            requestor=None,
                            email_cc_address=None,
                            approver=u"approver"):
    """Create an approval request to be sent to approver."""
    if not requestor:
      requestor = self.test_username

    self.CreateUser(requestor)
    self.CreateUser(approver)

    args = api_user.ApiCreateClientApprovalArgs(
        client_id=client_id,
        approval=api_user.ApiClientApproval(
            reason=reason,
            notified_users=[approver],
            email_cc_addresses=([email_cc_address]
                                if email_cc_address else [])))
    handler = api_user.ApiCreateClientApprovalHandler()
    result = handler.Handle(
        args, context=api_call_context.ApiCallContext(username=requestor))

    return result.id

  def GrantClientApproval(self,
                          client_id,
                          requestor=None,
                          approval_id=None,
                          approver=u"approver",
                          admin=True):
    """Grant an approval from approver to delegate.

    Args:
      client_id: Client id.
      requestor: username string of the user receiving approval.
      approval_id: id of the approval to grant.
      approver: username string of the user granting approval.
      admin: If True, make approver an admin user.

    Raises:
      ValueError: if approval_id is empty.
    """
    if not approval_id:
      raise ValueError("approval_id can't be empty.")

    if not requestor:
      requestor = self.test_username

    self.CreateUser(requestor)
    if admin:
      self.CreateAdminUser(approver)
    else:
      self.CreateUser(approver)

    if not requestor:
      requestor = self.test_username

    args = api_user.ApiGrantClientApprovalArgs(
        client_id=client_id, username=requestor, approval_id=approval_id)
    handler = api_user.ApiGrantClientApprovalHandler()
    handler.Handle(
        args, context=api_call_context.ApiCallContext(username=approver))

  def RequestAndGrantClientApproval(self,
                                    client_id,
                                    requestor=None,
                                    reason="Running tests",
                                    approver=u"approver",
                                    admin=True):
    """Request and grant client approval for a given client."""

    approval_id = self.RequestClientApproval(
        client_id, requestor=requestor, approver=approver, reason=reason)
    self.GrantClientApproval(
        client_id,
        requestor=requestor,
        approval_id=approval_id,
        approver=approver,
        admin=admin)
    return approval_id

  def ListClientApprovals(self, requestor=None):
    requestor = requestor or self.test_username
    handler = api_user.ApiListClientApprovalsHandler()
    return handler.Handle(
        api_user.ApiListClientApprovalsArgs(),
        context=api_call_context.ApiCallContext(username=requestor)).items

  def RequestHuntApproval(self,
                          hunt_id,
                          requestor=None,
                          reason="Running tests",
                          email_cc_address=None,
                          approver=u"approver"):
    """Request hunt approval for a given hunt."""

    if not requestor:
      requestor = self.test_username

    self.CreateUser(requestor)
    self.CreateUser(approver)

    args = api_user.ApiCreateHuntApprovalArgs(
        hunt_id=hunt_id,
        approval=api_user.ApiHuntApproval(
            reason=reason,
            notified_users=[approver],
            email_cc_addresses=([email_cc_address]
                                if email_cc_address else [])))
    handler = api_user.ApiCreateHuntApprovalHandler()
    result = handler.Handle(
        args, context=api_call_context.ApiCallContext(username=requestor))

    return result.id