<?php

/**
 * ALERT! Requires settings.json file in the static folder!
 */

const GALLERY_UPLOAD_PATH = "gallery-uploads";
const GALLERY_ITEM_SIZE_THUMB = 720;
const GALLERY_ITEM_SIZE_DIST = 4096;
const SETTINGS_STATIC_JSON_PATH = "../../static/settings.json";

header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");

include_once '../../config/database.php';
include_once '../objects/gallery_item.php';
include_once '../objects/user.php';
include_once '../objects/like.php';
include_once '../authenticator.php';

if ($_SERVER['REQUEST_METHOD'] != 'POST') {
    http_response_code(400);
    echo json_encode(array("error" => "Method not accepted."));
    exit();
}

$database = new Database();
$db = $database->getConnection();

$auth = new Authenticator($db);
$userId = $auth->authenticate();

// Check the image sharing is already enabled
$settings = json_decode(file_get_contents(SETTINGS_STATIC_JSON_PATH));
if (!$settings->photoSharingEnabled) {
    // Sharing not yet enabled: check the user is an Admin
    $stmt = User::get($db, $userId);
    $user = $stmt->fetch(PDO::FETCH_ASSOC);
    if (!$user || !array_key_exists('admin', $user))
        throw new Exception('unable to determine if user ' . $userId . ' is an admin');
    if (!$user['admin']) {
        http_response_code(403);
        echo json_encode(array("error" => "User doesn't have permission to publish an image"));
        exit();
    }
}

try {
    // Undefined | Multiple Files | $_FILES Corruption Attack
    // If this request falls under any of them, treat it invalid.
    if (
        !isset($_FILES['image']['error']) ||
        is_array($_FILES['image']['error'])
    ) {
        throw new InvalidArgumentException('Invalid parameters.');
    }

    // Check $_FILES['image']['error'] value.
    switch ($_FILES['image']['error']) {
        case UPLOAD_ERR_OK:
            break;
        case UPLOAD_ERR_NO_FILE:
            throw new RuntimeException('No file sent.');
        case UPLOAD_ERR_INI_SIZE:
        case UPLOAD_ERR_FORM_SIZE:
            throw new RuntimeException('Exceeded filesize limit.');
        default:
            throw new RuntimeException('Unknown errors.');
    }

    // DO NOT TRUST $_FILES['image']['mime'] VALUE !!
    // Check MIME Type by yourself.
    $finfo = new finfo(FILEINFO_MIME_TYPE);
    if (false === $ext = array_search(
        $finfo->file($_FILES['image']['tmp_name']),
        array(
            'jpg' => 'image/jpeg',
            'png' => 'image/png',
            'gif' => 'image/gif',
        ),
        true
    )) {
        throw new RuntimeException('Invalid file format.');
    }

    // Create upload directory (if not exists)
    $dir = GALLERY_UPLOAD_PATH;
    $dirRelPath = '../../' . $dir;

    // create new directory with 744 permissions if it does not exist yet
    // owner will be the user/group the PHP script is run under
    if ( !file_exists($dirRelPath) ) {
        if (!mkdir ($dirRelPath, 0744)) {
            throw new RuntimeException('Unable to create uploads folder: '.$dirRelPath);
        }
    }

    if ( !file_exists($_FILES['image']['tmp_name'])) {
        throw new RuntimeException('Failed not present in temp folder: '.$_FILES['image']['tmp_name']);
    }

    // Save original image
    $destFileName = sha1_file($_FILES['image']['tmp_name']);
    $destPath = sprintf('%s/%s.%s',
            $dirRelPath,
            $destFileName,
            $ext
        );
    if (!move_uploaded_file(
        $_FILES['image']['tmp_name'],
        $destPath
    )) {
        throw new RuntimeException('Failed to move uploaded file to '.$destPath);
    }

    // Create distribution image
    $distDestPath = sprintf('%s/%s_dist.%s',
		$dirRelPath,
		$destFileName,
		$ext
	);
    $retCodeThumb = exec('convert "'.$destPath.'" -auto-orient -resize '.GALLERY_ITEM_SIZE_DIST.'x'.GALLERY_ITEM_SIZE_DIST.' -quality 80 "'.$distDestPath.'"');
    if ($retCodeThumb)
        throw new RuntimeException("Unable to create distribution image");

    // Create thumb
    $thumbDestPath = sprintf('%s/%s_thumb.%s',
		$dirRelPath,
		$destFileName,
		$ext
	);
    $retCodeThumb = exec('convert "'.$destPath.'" -auto-orient -resize '.GALLERY_ITEM_SIZE_THUMB.'x'.GALLERY_ITEM_SIZE_THUMB.' -quality 80 "'.$thumbDestPath.'"');
    if ($retCodeThumb)
        throw new RuntimeException("Unable to create thumbnail");

    // Create gallery item with uploaded photo (only dist and thumb paths are saved to db)
	$gi = [];
    $gi['imageUrl'] = sprintf('/%s/%s_dist.%s',
        $dir,
        $destFileName,
        $ext
        );
    $gi['imageThumbUrl'] = sprintf('/%s/%s_thumb.%s',
        $dir,
        $destFileName,
        $ext
        );
    $gi['likes ']= 0;
    $gi['description'] = "";  // TODO
    $gi['author'] = $userId;

	$db->beginTransaction();

    if (!GalleryItem::create($db, $gi)){
        throw new RuntimeException("Unable to create GalleryItem.");
    }

    // Retrieve inserted item
	$newGiId = $database->conn->lastInsertId();
	$stmt = GalleryItem::readById($db, $userId, $newGiId);
	$row = $stmt->fetch(PDO::FETCH_ASSOC);
	if (!$row)
		throw new RuntimeException('Inserted row could not be found!');

    $result=array(
        "success" => TRUE,
        "errorMessage" => "",
        "filename" => $destFileName,
        "filepath" => $destPath,
        "record" => GalleryItem::fromRow($row)
    );

	$db->commit();

    // set response code - 200 OK
    http_response_code(200);

    // show products data in json format
    echo json_encode($result);

} catch (RuntimeException $e) {
    $err_item=array(
        "success" => FALSE,
        "errorMessage" => $e->getMessage(),
        "filename" => "",
        "filepath" => "",
    );
    echo json_encode($err_item);

}

?>
