<?php

namespace MatthiasWeb\RealMediaLibrary\lite\folder;

use Exception;
use MatthiasWeb\RealMediaLibrary\Core;
use MatthiasWeb\RealMediaLibrary\exception\FolderAlreadyExistsException;
use MatthiasWeb\RealMediaLibrary\Util;
// @codeCoverageIgnoreStart
\defined('ABSPATH') or die('No script kiddies please!');
// Avoid direct file request
// @codeCoverageIgnoreEnd
/** @internal */
trait Creatable
{
    // Documented in IFolderActions
    public function resetSubfolderOrder()
    {
        \delete_media_folder_meta($this->id, 'lastSubOrderBy');
        $this->debug("Deleted subfolder order of the folder {$this->id}", __METHOD__);
        return \true;
    }
    // Documented in IFolderActions
    public function orderSubfolders($orderby, $writeMetadata = \true)
    {
        $orders = self::getAvailableSubfolderOrders();
        $core = Core::getInstance();
        $core->debug("Try to order the subfolders of {$this->id} by {$orderby}...", __METHOD__);
        if (\in_array($orderby, \array_keys($orders), \true)) {
            global $wpdb;
            // Get order
            $split = \explode('_', $orderby);
            $order = $orders[$orderby];
            $direction = $split[1];
            $table_name = $core->getTableName();
            // Run SQL
            // phpcs:disable WordPress.DB.PreparedSQL
            $sql = $wpdb->prepare("UPDATE {$table_name} AS rmlo2\n                LEFT JOIN (\n                \tSELECT @rownum := @rownum + 1 AS ord, t.id\n                \tFROM ( SELECT rmlo.id\n                \t\tFROM {$table_name} AS rmlo\n                \t\tWHERE rmlo.parent = %d\n                \t\tORDER BY " . $order['sqlOrder'] . " {$direction} ) AS t, (SELECT @rownum := 0) AS r\n                ) AS rmlonew ON rmlo2.id = rmlonew.id\n                SET rmlo2.ord = rmlonew.ord\n                WHERE rmlo2.parent = %d", $this->id, $this->id);
            $wpdb->query($sql);
            // phpcs:enable WordPress.DB.PreparedSQL
            // Save in the metadata
            if ($writeMetadata) {
                \update_media_folder_meta($this->id, 'lastSubOrderBy', $orderby);
            }
            $core->debug('Successfully ordered folder', __METHOD__);
            return \true;
        } else {
            $core->debug("'{$orderby}' is not a valid order...", __METHOD__);
            return \false;
        }
    }
    /**
     * Check if the current folders parent is automatically ordered by a criteria so
     * the order can be applied. This should be called when the hierarchy of the
     * folder is changed or when a new folder is added to that parent.
     *
     * @return boolean
     */
    protected function applySubfolderOrderBy()
    {
        $parent = \wp_rml_get_object_by_id($this->getParent());
        if (!\is_rml_folder($parent)) {
            return \false;
        }
        $orderAutomatically = (bool) $parent->getRowData('subOrderAutomatically');
        if ($orderAutomatically) {
            $order = $parent->getRowData('lastSubOrderBy');
            if (!empty($order)) {
                $this->debug('New subfolder ' . $this->getId() . ' in folder ' . $parent->getId() . ", automatically order by {$order} ...", __METHOD__);
                return $parent->orderSubfolders($order, \false);
            }
        }
        return \false;
    }
    // Documented in IOverrideCreatable
    public function persistCheckParent()
    {
        // Check, if the parent exists
        $parentObj = \wp_rml_get_object_by_id($this->parent);
        if (!\is_rml_folder($parentObj)) {
            // translators:
            throw new Exception(\sprintf(\__('The parent %d does not exist.', RML_TD), $this->parent));
        }
        return $parentObj;
    }
    // Documented in IFolderActions
    public function reindexChildrens($resetData = \false)
    {
        global $wpdb;
        $table_name = $this->getTableName();
        // phpcs:disable WordPress.DB.PreparedSQL
        $sql = "UPDATE {$table_name} AS rml2\n            LEFT JOIN (\n                SELECT @rownum := @rownum + 1 AS nr, t.ID\n                FROM ( SELECT rml.id\n                    FROM {$table_name} AS rml\n                    WHERE rml.parent = {$this->id}\n                    ORDER BY rml.ord )\n                    AS t, (SELECT @rownum := 0) AS r\n            ) AS rmlnew ON rml2.id = rmlnew.id\n            SET rml2.ord = rmlnew.nr\n            WHERE rml2.parent = {$this->id}";
        $wpdb->query($sql);
        // phpcs:enable WordPress.DB.PreparedSQL
        $this->debug("Reindexed the childrens order of {$this->id}", __METHOD__);
        if ($resetData) {
            \wp_rml_structure_reset(null, \false);
        }
        return \true;
    }
    // Documented in IFolder
    public function isValidChildrenType($type)
    {
        $allowed = $this->getAllowedChildrenTypes();
        $this->debug("Check if children type '{$type}' of {$this->id}... is allowed here: " . ($allowed === \true ? 'All is allowed here' : 'Only ' . \json_encode($allowed) . ' is allowed here'), __METHOD__);
        return $allowed === \true ? \true : \in_array($type, $allowed, \true);
    }
    // Documented in IFolderActions
    public function setParent($id, $ord = -1, $force = \false)
    {
        // Get the parent id
        $this->debug("Try to set parent of {$this->id} from {$this->parent} to {$id}...", __METHOD__);
        // Get the parent object
        $parent = \wp_rml_get_object_by_id($id);
        if ($id === $this->parent) {
            $this->debug('The parent is the same, probably only the order is changed...', __METHOD__);
        } else {
            // Check if parent folder is given
            if ($parent === null) {
                throw new Exception(\__('The given parent does not exist to set the parent for this folder.', RML_TD));
            }
            // Check if allowed to change the parent
            if (!$force && $this->isRestrictFor('par')) {
                throw new Exception(\__('You are not allowed to change the parent for this folder.', RML_TD));
            }
            // Check, if the folder type is allowed here
            if (!$force && !$parent->isValidChildrenType($this->getType())) {
                throw new Exception(\__('The given parent does not allow the folder type.', RML_TD));
            }
            // Check, if the parent has already the given folder name
            if ($parent->hasChildren($this->name)) {
                throw new FolderAlreadyExistsException($id, $this->name);
            }
        }
        $newOrder = $ord > -1 ? $ord : $parent->getMaxOrder() + 1;
        $isRelocate = $id === $this->parent;
        /**
         * (Pro only) This action is called when a folder was moved in the folder tree. That
         * means the parent and order was changed.
         *
         * @param {IFolder} $folder The folder object
         * @param {int} $id The new parent folder id
         * @param {int} $order The (new) order number
         * @param {boolean} $force If true the relocating was forced
         * @hook RML/Folder/Move
         * @since 4.0.7
         * @since 4.12.1 This hook is only available in PRO-Version
         */
        \do_action($isRelocate ? 'RML/Folder/Relocate' : 'RML/Folder/Move', $this, $id, $newOrder, $force);
        $oldData = $this->getRowData();
        $beforeId = $this->parent;
        $this->parent = $id;
        $this->order = $newOrder;
        $this->debug("Use {$this->order} (passed {$ord} as parameter) as new order value", __METHOD__);
        // Save in database
        if ($this->id > -1) {
            global $wpdb;
            // Update childrens
            if ($beforeId !== $this->parent) {
                $this->updateThisAndChildrensAbsolutePath();
            }
            // Update order
            // phpcs:disable WordPress.DB.PreparedSQL
            $table_name = $this->getTableName();
            $wpdb->query($wpdb->prepare("UPDATE {$table_name} SET parent=%d, ord=%d WHERE id = %d", $id, $this->order, $this->id));
            // phpcs:enable WordPress.DB.PreparedSQL
            /**
             * (Pro only) This action is called when a folder was moved in the folder tree. That
             * means the parent and order was changed.
             *
             * @param {IFolder} $folder The folder object
             * @param {int} $id The new parent folder id
             * @param {int} $order The (new) order number
             * @param {boolean} $force If true the relocating was forced
             * @param {object} $oldData The old SQL row data (raw) of the folder
             * @hook RML/Folder/Moved
             * @since 4.12.1 This hook is only available in PRO-Version
             */
            \do_action($isRelocate ? 'RML/Folder/Relocated' : 'RML/Folder/Moved', $this, $id, $this->order, $force, $oldData);
            $this->debug('Successfully moved and saved in database', __METHOD__);
            Util::getInstance()->doActionAnyParentHas($this, 'Folder/RelocatedOrMoved', [$this, $id, $this->order, $force, $oldData]);
            $this->applySubfolderOrderBy();
        } else {
            $this->debug('Successfully setted the new parent', __METHOD__);
            $this->getAbsolutePath(\true, \true);
        }
        return \true;
    }
    // Documented in IFolderActions
    public function relocate($parentId, $nextFolderId = \false)
    {
        global $wpdb;
        // Collect data
        $table_name = $this->getTableName();
        $this->debug($parentId === $this->id ? "Start to relocate folder {$this->id} inside parent..." : "Start to relocate folder {$this->id} to parent {$parentId}...", __METHOD__);
        $this->debug($nextFolderId === \false ? 'The folder should take place at the end of the list...' : "The folder should take place before folder id {$nextFolderId}...", __METHOD__);
        $parent = $parentId === $this->id ? $this : \wp_rml_get_object_by_id($parentId);
        $next = $nextFolderId === \false ? null : \wp_rml_get_object_by_id($nextFolderId);
        // At end of the list
        try {
            if ($next === null && \is_rml_folder($parent)) {
                // Only set the parent
                $this->setParent($parent->id);
            } elseif (\is_rml_folder($next) && \is_rml_folder($parent)) {
                // Reindex and reget
                $parent->reindexChildrens();
                $_this = \wp_rml_structure_reset(null, \false, $this->id);
                $next = \wp_rml_get_object_by_id($next->id);
                // Get the order of the next folder
                $newOrder = $next->order;
                // Count up the next ids
                // phpcs:disable WordPress.DB.PreparedSQL
                $sql = "UPDATE {$table_name} SET ord = ord + 1 WHERE parent = {$parent->id} AND ord >= {$newOrder}";
                $wpdb->query($sql);
                // phpcs:enable WordPress.DB.PreparedSQL
                // Set the new parent
                $_this->setParent($parent->id, $newOrder);
            } else {
                // There is nothing given
                throw new Exception(\__('Something went wrong.', RML_TD));
            }
            $this->debug('Successfully relocated', __METHOD__);
            return \true;
        } catch (Exception $e) {
            $this->debug('Error: ' . $e->getMessage(), __METHOD__);
            return [$e->getMessage()];
        }
    }
    /**
     * Delete the subOrderAutomatically metadata when deleting the subfolder
     * order and also reset the subfolder order. It also handles the content order.
     *
     * @param int[] $meta_ids
     * @param int $object_id
     * @param string $meta_key
     */
    public static function deleted_realmedialibrary_meta($meta_ids, $object_id, $meta_key)
    {
        global $wpdb;
        if (empty($object_id)) {
            return;
        }
        if ($meta_key === 'lastSubOrderBy') {
            // The default is to order by ID ascending
            $folder = \wp_rml_get_object_by_id($object_id);
            if (\is_rml_folder($folder)) {
                $folder->orderSubfolders('id_asc', \false);
            }
            // phpcs:disable WordPress.DB.PreparedSQL
            $wpdb->query($wpdb->prepare('UPDATE ' . Core::getInstance()->getTableName() . ' SET ord=NULL, oldCustomOrder=NULL WHERE id=%d', $object_id));
            // phpcs:enable WordPress.DB.PreparedSQL
            \delete_media_folder_meta($object_id, 'subOrderAutomatically');
        }
        if ($meta_key === 'orderby') {
            // phpcs:disable WordPress.DB.PreparedSQL
            $wpdb->query($wpdb->prepare('UPDATE ' . Core::getInstance()->getTableName('posts') . ' SET nr=NULL, oldCustomNr=NULL WHERE fid=%d', $object_id));
            $wpdb->query($wpdb->prepare('UPDATE ' . Core::getInstance()->getTableName() . ' SET contentCustomOrder=0 WHERE id=%d', $object_id));
            // phpcs:enable WordPress.DB.PreparedSQL
            \delete_media_folder_meta($object_id, 'orderAutomatically');
        }
    }
}
