import os, sys
import json
from uuid import uuid4
from datetime import datetime
from decode_verify_jwt import decode_verify_jwt

from harvest.controllers.target_controller import TargetController
from harvest.controllers.place_controller import PlaceController
from harvest.controllers.photo_controller import PhotoController
from harvest.auth import Auth
from harvest.exception import ActionDeniedError, NotMeetRequirementsToDeleteError

class Work():
  project_id = None
  place_id = None
  target_id = None
  photo_id = None

  def __init__(self, host=None, port=None):
    self.place = PlaceController(host, port)
    self.target = TargetController(host, port)
    self.photo = PhotoController(host, port)
    self.auth = Auth(host, port)

  # common setters
  def set_user_id(self, user_id):
    self.auth.set_user_id(user_id)
    self.place.set_user_id(user_id)
    self.target.set_user_id(user_id)
    self.photo.set_user_id(user_id)

  def set_project_id(self, project_id):
    self.project_id = project_id
    self.place.set_project_id(project_id)
    self.target.set_project_id(project_id)
    self.photo.set_project_id(project_id)
    self.auth.set_project_id(project_id)
  
  def set_place_id(self, place_id):
    self.place_id = str(place_id)
    self.place.set_place_id(place_id)
    if self.place_id and self.target_id:
      self.auth.get_role()

  def set_target_id(self, target_id):
    self.target_id = str(target_id)
    self.target.set_target_id(target_id)
    self.photo.set_target_id(target_id)

  def set_photo_id(self, photo_id):
    self.photo_id = str(photo_id)
    self.photo.set_photo_id(photo_id)

  # common method
  def make_error_obj(self, exception):
    return {
        "title": exception.title,
        "message": exception.message,
        "code": exception.code
    }

  # shared actions
  def list_children(self, parent_place_id):
    if not self.auth.guard():
      raise ActionDeniedError()
    places = self.place.list_children(parent_place_id)
    targets = self.target.list_children(parent_place_id)
    return {
        "places": places,
        "targets": targets
    }

  # actions for place
  def create_place(self, name, place_id=None):
    if not self.auth.guard("worker"):
      raise ActionDeniedError()
    return self.place.create(name, place_id)

  def update_place(self, name, place_id=None):
    if not self.auth.guard("worker"):
      raise ActionDeniedError()
    return self.place.update_name(name)

  def delete_place(self, place_id=None):
    if not self.auth.guard("admin"):
      raise ActionDeniedError()
    children = self.list_children(place_id)
    if children["places"] or children["targets"]:
      raise NotMeetRequirementsToDeleteError()
    return self.place.delete(place_id)

  def show_place(self):
    if not self.auth.guard():
      raise ActionDeniedError()
    return self.place.show()

  # actions for target
  def create_target(self, name, place_id=None):
    if not self.auth.guard("worker"):
      raise ActionDeniedError()
    return self.target.create(name, place_id)

  def update_target(self, name):
    if not self.auth.guard("worker"):
      raise ActionDeniedError()
    return self.target.update_name(name)

  def delete_target(self, target_id):
    if not self.auth.guard("admin"):
      raise ActionDeniedError()
    return self.target.delete(target_id)

  def show_target(self):
    if not self.auth.guard():
      raise ActionDeniedError()
    return self.target.show()

  # actions for photo
  def create_photo(self, target_id, type, data):
    if not self.auth.guard("reporter"):
      raise ActionDeniedError()
    return self.photo.create(target_id, type, data)

  def update_photo(self, target_id, type, photo_id):
    if not self.auth.guard("worker"):
      raise ActionDeniedError()
    return self.photo.update_adopt(target_id, type, photo_id)

  def delete_photo(self, target_id, photo_id):
    if not self.auth.guard("admin"):
      raise ActionDeniedError()
    return self.photo.delete(target_id, photo_id)

  def show_photo(self, photo_id, encode=True):
    if not self.auth.guard():
      raise ActionDeniedError()
    return self.photo.show(photo_id, encode=encode)
