<?php

namespace Mailbox\Application;

use Mailbox\Application\Exceptions\MessageNotFound;
use Mailbox\Domain\MailBox\MailBox;
use Mailbox\Domain\MailBox\MailBoxCollection;
use Mailbox\Domain\MailBox\Contracts\MailBoxCriteriaInterface;
use Mailbox\Domain\Message\Contracts\MessageRepositoryInterface;
use Mailbox\Domain\Message\Message;
use Mailbox\Domain\Message\MessageCollection;
use Mailbox\Infrastructure\Repositories\RepositoryException;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Psr\Log\NullLogger;
use Mailbox\Application\MailBoxException;

/**
 *
 * Class MailBoxService
 * @package Mailbox\Application
 */
class MailBoxService implements LoggerAwareInterface
{
    use LoggerAwareTrait;

    protected $repository;

    protected $logger;

    public function __construct(MessageRepositoryInterface $repository)
    {
        $this->repository = $repository;
        $this->logger = new NullLogger();
    }


    /**
     * @param MessageSearchCriteria $searchCriteria
     * @return MessageCollection
     */
    public function getMessagesByCriteria(MessageSearchCriteria $searchCriteria): MessageCollection
    {

        try {
            $messages = $this->repository->findByCriteria($searchCriteria);
        } catch (RepositoryException $ex) {
            throw new MailBoxException($ex->getMessage());
        }

        return $messages;
    }

    /**
     * @param int $messageId
     * @return Message
     */
    public function getMessageById(int $messageId): Message
    {

        try {
            $message = $this->repository->findById($messageId);
        } catch (RepositoryException $ex) {
            throw new MailBoxException($ex->getMessage());
        }

        if (!$message) {
            throw new MessageNotFound($messageId);
        }

        return $message;
    }

    /**
     * @param int $uId
     * @return Message
     */
    public function getMessageByUid(int $uId): Message
    {
        try {
            $messages = $this->repository->findByCriteria(
                MessageSearchCriteria::create()
                    ->setFilterByUid($uId)
                    ->setLimit(1)
            );
        } catch (RepositoryException $ex) {
            throw new MailBoxException($ex->getMessage());
        }

        $message = $messages->current();

        if (!$message) {
            throw new MessageNotFound($uId, true);
        }

        return $message;
    }


    /**
     * @param MailBoxCriteriaInterface $mailBoxCriteria
     * @return MailBoxCollection
     */
    public function getMailBoxesByCriteria(MailBoxCriteriaInterface $mailBoxCriteria): MailBoxCollection
    {
        try {
            $boxes = $this->repository->findMailBoxesByCriteria($mailBoxCriteria);
        } catch (RepositoryException $ex) {
            throw new MailBoxException($ex->getMessage());
        }

        return $boxes;
    }


    /**
     * @param string $messageId
     * @param string $mailBoxName
     * работа с id работает не стабильно так как id меняются при высокой активности входящих писем
     * @deprecated
     */
    public function moveMessageToMailBoxById(string $messageId, string $mailBoxName): void
    {

        if (!$message = $this->getMessageById($messageId)) {
            throw new MessageNotFound($messageId);
        }

        $this->moveMessageToMailBox($message, $mailBoxName);
    }


    /**
     * @param Message $message
     * @param string $mailBoxName
     */
    public function moveMessageToMailBox(Message $message, string $mailBoxName): void
    {
        $mailBoxes = $this->getMailBoxesByCriteria((new MailBoxSearchCriteria())->setFilterByName($mailBoxName));

        if (!$mailBox = $mailBoxes->current()) {
            throw new MailBoxException($mailBoxName);
        }

        try {
            $this->repository->moveMessage($message, $mailBox);
        } catch (RepositoryException $ex) {
            throw new MailBoxException($ex->getMessage());
        }
    }
}
