text: #      Author: Birnadin Erick
  #      Copyright © 2021. All rights are reserved by Birnadin Erick.
  #      This script can be used without any written acknowledgement from author for personal or commercial purpose.
  #
  from datetime import datetime as dt
  
  from flask import abort
  from flask_restful import Resource
  from flask_restful.reqparse import RequestParser
  
  from utility.helpers import hash_passwd, create_id, verify_passwd
  from utility.mongo_api import mdb_api
  
  hunters = mdb_api["BugBounty"]["Hunters"]
  
  hunter_post_args = RequestParser()
  hunter_get_args = RequestParser()
  hunter_patch_args = RequestParser()
  hunter_del_args = RequestParser()
  
  hunter_post_args.add_argument("hname", type=str, help="H_404_hn", required=True)
  hunter_post_args.add_argument("ptxt", type=str, help="H_404_ptxt", required=True)
  hunter_post_args.add_argument("fname", type=str, help="H_404_fn", required=True)
  hunter_post_args.add_argument("lname", type=str)
  
  hunter_get_args.add_argument("h_id", type=int, help="U_404_hid", required=True)
  
  hunter_patch_args.add_argument("h_id", type=int, help="H_404_hid", required=True)
  hunter_patch_args.add_argument("poly", type=int, help="H_404_poly", required=True)
  hunter_patch_args.add_argument("opts", type=str, help="H_404_opt", required=True)
  hunter_patch_args.add_argument("params", type=str, help="H_404_p", required=True)
  
  hunter_del_args.add_argument("h_id", type=int, help="H_404_hid", required=True)
  hunter_del_args.add_argument("ptxt", type=str, help="H_404_ptxt", required=True)
  
  
  class ResourceHunter(Resource):
      @staticmethod
      def post():
          args = hunter_post_args.parse_args()
          h = hunters.find_one({'hname': {'$eq': args["hname"]}})
  
          try:
              if h.inserted_id:
                  abort(409, "H_409_hn_taken")
          except AttributeError:
              pass
  
          hunter = {
              '_id': create_id(args["hname"]),
              'hname': args["hname"],
              'fname': args["fname"],
              'phash': hash_passwd(args["ptxt"]),
              'cstamp': dt.now().timestamp(),
              'c_ids': [],
              'bo_ids': []
          }
  
          if args["lname"]:
              hunter["lname"] = args["lname"]
  
          try:
              hunters.insert_one(hunter)
          except Exception as e:
              abort(501, e.__str__())
          else:
              del hunter['phash']
              return hunter, 201
  
      @staticmethod
      def get():
          # TODO: authenticate the req b4 processing via utility uri
          args = hunter_get_args.parse_args()
          try:
              hunter = hunters.find_one({'_id': {'$eq': args["h_id"]}})
              if hunter is not None:
                  del hunter["phash"]
              else:
                  abort(404, "Hunter you askes for may have been deleted?!")
          except Exception as e:
              abort(500, e.__str__())
          else:
              del args
              return hunter, 200
  
      def patch(self):
          """
          TODO: authenticate the req b4 processing via utility uri
          patchable attrs:-
              ~ b_ids --> 0
              ~ c_ids --> 1
              ~ lname --> 2
              ~ fname --> 3
              ~ ptxt  --> 4
          """
          args = hunter_patch_args.parse_args()
  
          if not args["poly"]:
              self.update_per_opt(
                  opt=int(args["opts"]),
                  arg=args["params"],
                  h_id=args["h_id"]
              )
          else:
              os = [int(o) for o in args["opts"].split("|")]
              ps = args["params"].split("|")
              for o in os:
                  self.update_per_opt(
                      opt=o,
                      arg=ps[os.index(o)],
                      h_id=args["h_id"]
                  )
  
          h = hunters.find_one({'_id': args["h_id"]})
          del h["phash"]
          return h, 200
  
      @staticmethod
      def delete():
          args = hunter_del_args.parse_args()
          h = hunters.find_one({'_id': args["h_id"]})
          if verify_passwd(args["ptxt"], h['phash']):
              try:
                  hunters.delete_one({'_id': {'$eq': args["h_id"]}})
              except Exception as e:
                  abort(500, e.__str__())
              else:
                  return "deletion success", 200
          abort(403, "U_403_xpass")
  
      @staticmethod
      def update_per_opt(opt, arg, h_id):
          if opt == 0:
              try:
                  if "," in arg:
                      b_ids = [int(b) for b in arg.split(",")]
                  else:
                      b_ids = [int(arg)]
  
                  hunters.update_one(
                      {'_id': {'$eq': h_id}},
                      {'$set': {'b_ids': b_ids}}
                  )
              except AttributeError or TypeError:
                  abort(403, "U_403_p")
              except Exception as e:
                  abort(500, e.__str__())
  
          elif opt == 1:
              try:
                  if "," in arg:
                      c_ids = [int(b) for b in arg.split(",")]
                  else:
                      c_ids = [int(arg)]
  
                  hunters.update_one(
                      {'_id': {'$eq': h_id}},
                      {'$set': {'c_ids': c_ids}}
                  )
              except AttributeError or TypeError:
                  abort(403, "U_403_p")
              except Exception as e:
                  abort(500, e.__str__())
  
          elif opt == 2:
              try:
                  hunters.update_one(
                      {'_id': {'$eq': h_id}},
                      {'$set': {'lname': arg}}
                  )
              except Exception as e:
                  abort(500, e.__str__())
  
          elif opt == 3:
              try:
                  hunters.update_one(
                      {'_id': {'$eq': h_id}},
                      {'$set': {'fname': arg}}
                  )
              except Exception as e:
                  abort(500, e.__str__())
  
          elif opt == 4:
              try:
                  if "," in arg:
                      ins = arg.split(",")
                      if len(ins) < 2:
                          abort(403, "U_403_p")
  
                      h = hunters.find_one({'_id': {'$eq': h_id}})
  
                      if verify_passwd(ins[0], h['phash']):
                          hunters.update_one(
                              {'_id': {'$eq': h_id}},
                              {'$set': {'phash': hash_passwd(ins[1])}}
                          )
                          del h, ins
                      else:
                          del h, ins
                          abort(403, "Wrong Current Password")
                  else:
                      abort(403, "U_403_p")
              except Exception as e:
                  abort(500, e.__str__())
  
          else:
              abort(403, "U_403_p")
  