from src import formatting
from src import schema
from time import time
from src import db


endpoints = {
    "check_auth":      ["user", "auth_hash"],
    "is_registered":   ["target_user"],
    "is_admin":        ["target_user"],
    "thread_index":    [],
    "thread_load":     ["thread_id"],
    "thread_create":   ["title", "body", "tags"],
    "thread_reply":    ["thread_id", "body"],
    "edit_post":       ["thread_id", "post_id", "body"],
    "edit_query":      ["thread_id", "post_id"],
    "can_edit":        ["thread_id", "post_id"],
    "user_register":   ["user", "auth_hash", "quip", "bio"],
    "user_get":        ["target_user"],
    "user_name_to_id": ["target_user"]
}


authless = [
    "is_registered",
    "user_register"
]


# this is not actually an endpoint, but produces a required
# element of thread responses.
def create_usermap(thread, index=False):
    if index:
        return {user: db.user_get(user) for user in
                  {i["author"] for i in thread}}

    result = {reply["author"] for reply in thread["replies"]}
    result.add(thread["author"])
    return {x: db.user_get(x) for x in result}


def user_name_to_id(json):
    """
    Returns a string of the target_user's ID when it is
    part of the database: a non-existent user will return
    a boolean false.
    """
    return db.user_resolve(json["target_user"])


def is_registered(json):
    """
    Returns true or false whether target_user is registered
    in the system. This function only takes usernames: not
    user IDs.
    """
    return bool(db.USERDB["namemap"].get(json["target_user"]))


def check_auth(json):
    "Returns true or false whether auth_hashes matches user."
    return bool(db.user_auth(json["user"], json["auth_hash"]))


def is_admin(json):
    """
    Returns true or false whether target_user is a system
    administrator. Takes a username or user ID. Nonexistent
    users return false.
    """
    user = db.user_resolve(json["target_user"])
    if user:
        return db.user_is_admin(user)
    return False


def user_register(json):
    """
    Registers a new user into the system. Returns the new internal user
    object on success, or an error response.

    auth_hash should be a hexadecimal SHA-256 string, produced from a
      UTF-8 password string.

    user should be a string containing no newlines and
      under 24 characters in length.

    quip is a string, up to 120 characters, provided by the user
      the acts as small bio, suitable for display next to posts
      if the client wants to. Whitespace characters besides space
      are not allowed. The string may be empty.

    bio is a string, up to 4096 chars, provided by the user that
      can be shown on profiles. There are no character type limits
      for this entry. The string may be empty.

    All errors for this endpoint with code 4 should show the
    description direcrtly to the user.

    """

    return schema.response(
        db.user_register(
            json["auth_hash"],
            json["user"],
            json["quip"],
            json["bio"]))


def user_get(json):
    """
    On success, returns an external user object for target_user (ID or name).
    If the user isn't in the system, returns false.
    """
    user = db.user_resolve(json["target_user"])
    if not user:
        return False
    return db.user_get(user)


def thread_index(json):
    index = db.thread_index(markup=not json.get("nomarkup"))
    return schema.response({"threads": index}, create_usermap(index, True))


def thread_load(json):
    thread = db.thread_load(json["thread_id"], not json.get("nomarkup"))
    if not thread:
        return schema.error(7, "Requested thread does not exist")
    return schema.response(thread, create_usermap(thread))


def thread_create(json):
    thread = db.thread_create(
        json["user"],
        json["body"],
        json["title"],
        json["tags"])
    return schema.response(thread)


def thread_reply(json):
    reply = db.thread_reply(
        json["thread_id"],
        json["user"],
        json["body"])
    return schema.response(reply)


def edit_query(json):
    return db.edit_handler(json)[1]


def can_edit(json):
    return db.edit_handler(json)[0]


def edit_post(json):
    thread = db.thread_load(json["thread_id"])
    admin = db.user_is_admin(json["user"])
    target_id = json["post_id"]
    ok, obj = db.edit_handler(json, thread)

    if ok:

        if json.get("reformat"):
            json["body"] = formatting.parse(json["body"])

        obj["body"] = json["body"]
        obj["lastmod"] = time()
        obj["edited"] = True
        db.thread_dump(json["thread_id"], thread)

    return obj
