<?php

namespace Api\Posts;

use Exception;
use Khofmann\Api\Api;
use Khofmann\ApiError\ApiError;
use Khofmann\Input\Input;
use Khofmann\Models\Post\Post;
use Khofmann\Models\User\User;
use Khofmann\Request\Request;
use Khofmann\Response\Response;

/**
 * Posts route handlers
 */
class Posts extends Api
{
  /**
   * Posts GET handler
   *
   * Lists posts. Optional parameters are `l` (limit of returned list) and `p` (page, i.e. offset).
   */
  public function get()
  {
    // Fetch and constrain all parameters.
    $page = max(0, intval(Input::get("p", 0)));
    $limit = constrain(0, 30, intval(Input::get("l", 10)));
    $authed = Request::token() !== null;

    // Return list of posts.
    Response::json(Post::list($page, $limit, $authed));
  }

  /**
   * Posts POST handler
   *
   * Create a new posts. Required inputs are `content`. Optional parameter is `l` (limit of list for which the returned pages is calculated).
   *
   * Returns created post and resulting amount of pages for a given limit.
   *
   * @throws 400 Missing fields
   */
  public function post(): void
  {
    // Fetch all required inputs.
    // Throw 400 error if a required one is missing.
    $content = Input::post("content");
    // This one is optional
    $limit = constrain(0, 30, intval(Input::get("l", 10)));
    if (empty($content)) throw ApiError::missingField(["content"]);

    // Get logged in user
    $self = User::getByToken(Request::token());

    // Try to create a new post for logged in user.
    try {
      Response::json(Post::create($self, $content, $limit));
    } catch (Exception $err) {
      switch ($err->getMessage()) {
        default:
          throw $err;
      }
    }
  }

  /**
   * Posts PATCH handler
   *
   * Update a posts.
   *
   * Returns updated post.
   *
   * @param mixed $id ID of post to update
   *
   * @throws 401 Not authorized (trying to edit a different users post if not admin)
   * @throws 404 Post not found
   * @throws 500 Failed to update user
   */
  public function patch($id): void
  {
    // Fetch all inputs.
    $content = Input::patch("content");

    // Fetch authed user.
    $self = User::getByToken(Request::token());

    try {
      // Try fetch the post in question, 404 if not found.
      $post = Post::getByID($id);

      // Throw 400 if we aren't admin but trying to edit another users post.
      if (!$self->getIsAdmin() && $post->getUser()->getID() !== $self->getID()) throw ApiError::notAllowed("Not allowed");

      // Try update.
      Response::json($post->update($content));
    } catch (Exception $err) {
      switch ($err->getMessage()) {
        case "NotFound":
          throw ApiError::notFound("post");
        default:
          // Due to how the failed field is handled, it's ApiError is inside the models update
          throw $err;
      }
    }
  }

  /**
   * Posts DELETE handler
   *
   * Delete a post. Optional parameter is `l` (limit of list for which the returned pages is calculated).
   *
   * Returns deleted post and resulting amount of pages for a given limit.
   *
   * @param mixed $id ID of posts to delete
   * 
   * @throws 404 Post not found
   */
  public function delete($id): void
  {
    // Fetch and constrain all parameters.
    $limit = constrain(0, 30, intval(Input::get("l", 10)));
    // Try delete, 404 if post was not found.
    try {
      Response::json(Post::getByID($id)->delete($limit));
    } catch (Exception $err) {
      switch ($err->getMessage()) {
        case "NotFound":
          throw ApiError::notFound("post");
        default:
          throw $err;
      }
    }
  }
}
