<?php

namespace Velis\Bpm\Ticket\Post;

use Exception;
use Inspection\Ticket\Task;
use RuntimeException;
use Velis\App;
use Velis\Arrays;
use Velis\Bpm\Ticket\Post;
use Velis\Bpm\Ticket\Ticket;
use Velis\DuplicateRequestException;
use Velis\Exception\BusinessLogicException;
use Velis\Filter;
use Velis\Lang;
use Velis\Model\DataObject\NoColumnsException;
use Velis\Model\File as FileModel;
use Velis\Model\RelationLoader\Relations\HasOneRelation;
use Velis\Model\Sanitizable;
use Velis\ParameterBag;

/**
 * Ticket post uploaded file
 * @author Olek Procki <olo@velis.pl>
 */
class File extends FileModel implements Sanitizable
{
    /**
     * Filter list params by default
     * @var bool
     */
    protected static $_filterListParams = true;


    /**
     * Related post
     * @var Post
     */
    protected $_post;


    /**
     * @var Ticket
     */
    protected $_ticket;

    protected ?Task $task;

    /**
     * @var bool
     * Rotate and create thumbnails flag
     */
    protected $_proceedImage = true;


    /**
     * @return string
     */
    protected function _getTableName()
    {
        return 'app.ticket_post_file_tab';
    }


    /**
     * Uploads post file
     *
     * @param array|null $versionInfo
     * @return $this
     * @throws DuplicateRequestException
     */
    public function add($versionInfo = null)
    {
        $commit = self::$_db->startTrans();

        try {
            if ($versionInfo) {
                if (!($versionedFile = self::instance($versionInfo['versionedFileId']))) {
                    throw new RuntimeException('Nie odnaleziono pliku, którego ma dotyczyć nowa wersja!');
                }
                $query = '
                    UPDATE app.ticket_post_file_tab
                    SET
                        version_is_current = 0,
                        version_no = COALESCE(version_no, 1)
                    WHERE (parent_ticket_post_file_id = :parent_ticket_post_file_id OR ticket_post_file_id = :parent_ticket_post_file_id)
                ';

                $params = [
                    'parent_ticket_post_file_id' => $versionedFile->id(),
                ];

                self::$_db->execDML($query, $params);

                $this['version_no'] = self::$_db->getOne('
                    SELECT MAX(version_no) + 1
                    FROM app.ticket_post_file_tab
                    WHERE (
                        parent_ticket_post_file_id = :parent_ticket_post_file_id
                        OR ticket_post_file_id = :parent_ticket_post_file_id
                    )
                ', $params);

                $this['version_is_current'] = 1;
                $this['version_comment'] = $versionInfo['versionComment'];
                $this['parent_ticket_post_file_id'] = $versionedFile->getParentId() ?: $versionedFile->id();
            }

            parent::add(true);

            if ($commit) {
                self::$_db->commit();
            }

            return $this;
        } catch (Exception $e) {
            if ($commit) {
                self::$_db->rollback();
            }

            throw $e;
        }
    }


    /**
     * Just insert new row to database
     * @return $this
     * @throws DuplicateRequestException
     */
    public function insert()
    {
        return parent::add(true);
    }


    /**
     * Removes database row
     * @return bool
     */
    public function remove($erase = true)
    {
        return parent::_remove($erase);
    }


    /**
     * Returns file download path
     * @return string
     */
    public function getDownloadUrl($thumb = '')
    {
        return '/ticket/post/download-file?fileId=' . $this->id() . (($thumb) ? '&thumb=' . $thumb : '');
    }


    /**
     * Returns webdav link
     * @return string
     */
    public function getWebdavLink()
    {
        return '/files/file/' . $this->id() . '-' . $this['filename'];
    }


    /**
     * Returns storage directory
     * @return string
     */
    protected function _getStorageDir()
    {
        $this->unstash();

        return App::$config->upload->postFilesDir
            . DIRECTORY_SEPARATOR . substr($this['date_entered'] ?: $this->getPost()->date_entered, 0, 4)
            . DIRECTORY_SEPARATOR;
    }


    /**
     * Returns ticket post
     * @return Post
     */
    public function getPost(): Post
    {
        if (!isset($this->_post)) {
            $this->_post = Post::bufferedInstance($this->ticket_post_id);
        }
        return $this->_post;
    }

    /**
     * @return Post[]
     * @throws \Velis\Exception
     */
    public static function loadPost(array $files): array
    {
        $ids = Arrays::getColumn($files, 'ticket_post_id');
        $posts = Post::instance($ids);

        foreach ($files as $file) {
            $file->_post = $posts[$file->ticket_post_id];
        }

        return $posts;
    }


    /**
     * Sets post instance
     * @param Post $post
     * @throws BusinessLogicException
     */
    public function setPost(Post $post)
    {
        if ($this->ticket_post_id == $post->id()) {
            $this->_post = $post;
        } else {
            throw new BusinessLogicException(Lang::get('TICKET_POST_INVALID_ID'));
        }
    }


    /**
     * Returns parent file id
     * @return int
     */
    public function getParentId()
    {
        return $this->parent_ticket_post_file_id;
    }


    /**
     * Returns version no
     * @return int
     */
    public function getVersion()
    {
        return $this->version_no;
    }

    /**
     * Returns true if file is current version
     * @return bool
     */
    public function isCurrent()
    {
        return $this->version_is_current || !strlen($this->version_no);
    }


    /**
     * Returns root id for file versioning
     * @return int
     */
    public function getVersionRootId()
    {
        return $this->getParentId() ?: $this->id();
    }


    /**
     * Returns ticket
     * @return Ticket
     * @throws NoColumnsException
     */
    public function getTicket()
    {
        if (!isset($this->_ticket)) {
            $this->_ticket = $this->getPost()->getTicket();
        }
        return $this->_ticket;
    }

    public function getTask()
    {
        if (!isset($this->task)) {
            $this->task = Task::instance($this->inspection_ticket_task_id);
        }

        return $this->task;
    }

    /**
     * @return Task[]
     */
    public static function loadTask(array $files): array
    {
        $ids = Arrays::getColumn($files, 'inspection_ticket_task_id');
        $tasks = Task::instance($ids);

        foreach ($files as $file) {
            $taskId = $file['inspection_ticket_task_id'];
            $file->task = $taskId ? $tasks[$taskId] : null;
        }

        return $tasks;
    }

    /**
     * Sets ticket instance
     * @param Ticket $ticket
     * @return $this
     * @throws BusinessLogicException
     */
    public function setTicket(Ticket $ticket)
    {
        if ($this['ticket_id'] && $this['ticket_id'] != $ticket->id()) {
            throw new BusinessLogicException(Lang::get('TICKET_INVALID_NO'));
        }
        $this->_ticket = $ticket;

        return $this;
    }


    /**
     * {@inheritDoc}
     */
    public static function getList($page = 1, $params = null, $order = 'ticket_post_file_id DESC', $limit = self::ITEMS_PER_PAGE, $fields = null)
    {
        $params = new ParameterBag($params);

        if ($params['date_entered_from'] && Filter::validateDate($params['date_entered_from'])) {
            self::$_listConditions[] = "date_entered >= :date_entered_from";
            self::$_listParams['date_entered_from'] = $params['date_entered_from'];
        }

        if ($params['date_entered_to'] && Filter::validateDate($params['date_entered_to'])) {
            self::$_listConditions[] = "date_entered <= :date_entered_to";
            self::$_listParams['date_entered_to'] = $params['date_entered_to'];
        }

        if ($params['show_current_version']) {
            self::$_listConditions[] = '(version_is_current IS NULL OR version_is_current=1)';
        }

        return parent::getList($page, $params, $order, $limit, $fields);
    }


    /**
     * Duplicate file instance
     * @param Post $post
     * @param Post|null $relatedTicketPost
     * @return File
     * @throws NoColumnsException
     * @throws DuplicateRequestException
     */
    public function duplicate(Post $post, $relatedTicketPost = null)
    {
        if ($relatedTicketPost instanceof Post) {
            $this->setPost($relatedTicketPost);
        }

        $file = new File($this->getArrayCopy());

        unset($file['ticket_post_file_id']);

        $file['ticket_post_id'] = $post->id();
        $file['hash'] = md5('ticket-post-file-' . microtime());
        $file->setPost($post);

        $file->setContents($this->getContents());
        $file->add();

        return $file;
    }

    public function relationPost(): HasOneRelation
    {
        return $this->hasOne(Post::class, 'ticket_post_id');
    }
}
