<?php

namespace App\Library\Imap;

use App\Library\Imap\Message\MessageInterface;
use Illuminate\Support\Collection;
use App\Library\Imap\Message\Message;

class Client {
  protected $_connection;
  protected $_prototype;
  protected $_spec;
  protected $_currentMailbox;

  public function __construct($connection, array $spec) {
    if (!is_resource($connection)) {
      throw new \InvalidArgumentException("Musíte předat prostředek spojení se serverem IMAP.");
    }

    $this->_prototype = new Message($connection);

    $this->_connection = $connection;
    $this->_spec = $spec;
    $this->_currentMailbox = $spec['mailbox'];
  }

  public function getCurrentMailbox() : string {
    return $this->_currentMailbox;
  }

  public function setCurrentMailbox(string $box, int $options = 0, int $n_retries = 0) : self {
    $this->_currentMailbox = $box;

    if (!imap_reopen($this->_connection, $this->getServerRef() . $this->_currentMailbox, $options, $n_retries)) {
      throw new ImapException("Nepodařilo se otevřít e-mailovou schránku: $box");
    }

    return $this;
  }

  public function setPrototype(MessageInterface $obj) : self {
    $this->_prototype = $obj;
    return $this;
  }

  public function getPrototype() : MessageInterface {
    return clone $this->_prototype;
  }
  
  public function deleteMessage($id, int $options = 0) : self {
    imap_delete($this->_connection, $id, $options);
    return $this;
  }

  public function getMessage($id, int $options = 0) : \App\Library\Imap\Message\MessageInterface {
    $overview = imap_fetch_overview($this->_connection, $id, $options);

    if (empty($overview)) {
      return $this->getPrototype();
    }

    $overview = array_pop($overview);

    $retval = $this->getPrototype();

    $retval->setSubject(isset($overview->subject) ? $overview->subject : '')
           ->setFrom(isset($overview->from) ? $overview->from : '')
           ->setTo(isset($overview->to) ? $overview->to : '')
           ->setDate($overview->date)
           ->setMessageId($overview->message_id)
           ->setSize($overview->size)
           ->setUID($overview->uid)
           ->setMessageNo($overview->msgno);

    return $retval;
  }

  protected function getServerRef() {
    $serverRef = '{' . $this->_spec['hostname'];

    if (!empty($this->_spec['port'])) {
      $serverRef .= ':' . $this->_spec['port'];
    }

    if (!empty($this->_spec['path'])) {
      $serverRef .= $this->_spec['path'];
    }

    $serverRef .= '}';

    return $serverRef;
  }

  public function getMailboxes($pattern = '*') {
    $serverRef = $this->getServerRef();

    $result = imap_list($this->_connection, $serverRef, $pattern);

    if (!is_array($result)) {
      return [];
    }

    $retval = [];

    foreach ($result as $mailbox) {
      $retval[] = str_replace($serverRef, '', $mailbox);
    }

    return $retval;
  }

  public function formatMailbox($mailbox) {
    return mb_convert_encoding($mailbox, 'UTF-8', 'UTF7-IMAP');
  }

  public function getCount() {
    $boxInfo = imap_check($this->_connection);

    return $boxInfo->Nmsgs;
  }

  public function getPage(int $page = 1, int $perPage = 25, $options = 0) : \Illuminate\Support\Collection {
    $boxInfo = imap_check($this->_connection);

    $start = $boxInfo->Nmsgs - ($perPage * $page);
    $end = $start + ($perPage - (($page > 1) ? 1 : 0) );

    if ($start < 1) {
      $start = 1;
    }

    $overview = imap_fetch_overview($this->_connection, "$start:$end", $options);
    $overview = array_reverse($overview);

    $collection = new Collection();

    foreach ($overview as $key => $msg) {
      $msgObj = $this->getPrototype();

      $msgObj->setSubject(isset($msg->subject) ? $msg->subject : '')
             ->setFrom(isset($msg->from) ? $msg->from : '')
             ->setTo(isset($msg->to) ? $msg->to : '')
             ->setDate($msg->date)
             ->setMessageId($msg->message_id)
             ->setSize($msg->size)
             ->setUID($msg->uid)
             ->setMessageNo($msg->msgno);

      if (isset($msg->references)) {
        $msgObj->setReferences($msg->references);
      }

      if (isset($msg->in_reply_to)) {
        $msgObj->setInReplyTo($msg->in_reply_to);
      }

      $collection->put($key, $msgObj);
    }

    return $collection;
  }
}

?>
