<?php

use MailSo\Imap\Enumerations\FolderType;
use MailSo\Imap\Enumerations\MetadataKeys;

class MailboxDetectPlugin extends \RainLoop\Plugins\AbstractPlugin
{
	const
		NAME     = 'MailboxDetect',
		AUTHOR   = 'SnappyMail',
		URL      = 'https://snappymail.eu/',
		VERSION  = '2.6',
		RELEASE  = '2023-03-13',
		REQUIRED = '2.27.0',
		CATEGORY = 'General',
		LICENSE  = 'MIT',
		DESCRIPTION = 'Autodetect system folders and/or create them when needed';

	public function Init() : void
	{
		$this->addHook('json.after-folders', 'AfterFolders');
	}

	protected function configMapping() : array
	{
		return array(
			\RainLoop\Plugins\Property::NewInstance('autocreate_system_folders')->SetLabel('Autocreate system folders')
				->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL)
				->SetDefaultValue(false),
		);
	}

	protected function Logger() : \MailSo\Log\Logger
	{
		return $this->Manager()->Actions()->Logger();
	}

	public function AfterFolders(array &$aResponse)
	{
		if (!empty($aResponse['Result']['@Collection'])) {
			$oActions = \RainLoop\Api::Actions();
			$oAccount = $oActions->getAccountFromToken();
			if (!$oAccount) {
				$this->Logger()->Write('No Account');
				return;
			}
			$oSettingsLocal = $oActions->SettingsProvider(true)->Load($oAccount);
			$roles = [
				'inbox'   => false,
				'sent'    => !!$oSettingsLocal->GetConf('SentFolder', ''),
				'drafts'  => !!$oSettingsLocal->GetConf('DraftsFolder', ''),
				'junk'    => !!$oSettingsLocal->GetConf('JunkFolder', ''),
				'trash'   => !!$oSettingsLocal->GetConf('TrashFolder', ''),
				'archive' => !!$oSettingsLocal->GetConf('ArchiveFolder', '')
			];
			$types = [
				FolderType::SENT => 'sent',
				FolderType::DRAFTS => 'drafts',
				FolderType::JUNK => 'junk',
				FolderType::TRASH => 'trash',
				FolderType::ARCHIVE => 'archive'
			];
			$found = [
				'inbox'   => [],
				'sent'    => [],
				'drafts'  => [],
				'junk'    => [],
				'trash'   => [],
				'archive' => []
			];
			$aMap = $this->systemFoldersNames($oAccount);
			$sDelimiter = '';
			foreach ($aResponse['Result']['@Collection'] as $i => $folder) {
				$sDelimiter || ($sDelimiter = $folder['delimiter']);
				if ($folder['role']) {
					$roles[$folder['role']] = true;
				} else if (\in_array('\\sentmail', $folder['attributes'])) {
					$found['sent'][] = $i;
				} else if (\in_array('\\spam', $folder['attributes'])) {
					$found['junk'][] = $i;
				} else if (\in_array('\\bin', $folder['attributes'])) {
					$found['trash'][] = $i;
				} else if (\in_array('\\starred', $folder['attributes'])) {
					$found['flagged'][] = $i;
				} else {
					// Kolab
					$kolab = $folder['metadata'][MetadataKeys::KOLAB_CTYPE]
						?? $folder['metadata'][MetadataKeys::KOLAB_CTYPE_SHARED]
						?? '';
					if ('mail.inbox' === $kolab) {
						$found['inbox'][] = $i;
					} else if ('mail.sentitems' === $kolab /*|| 'mail.outbox' === $kolab*/) {
						$found['sent'][] = $i;
					} else if ('mail.drafts' === $kolab) {
						$found['drafts'][] = $i;
					} else if ('mail.junkemail' === $kolab) {
						$found['junk'][] = $i;
					} else if ('mail.wastebasket' === $kolab) {
						$found['trash'][] = $i;
					} else {
						$iFolderType = 0;
						if (isset($aMap[$folder['fullName']])) {
							$iFolderType = $aMap[$folder['fullName']];
						} else if (isset($aMap[$folder['name']]) || isset($aMap["INBOX{$folder['delimiter']}{$folder['name']}"])) {
							$iFolderType = $aMap[$folder['name']];
						}
						if ($iFolderType && isset($types[$iFolderType])) {
							$found[$types[$iFolderType]][] = $i;
						}
					}
				}
			}
			foreach ($roles as $role => $hasRole) {
				if ($hasRole) {
					unset($found[$role]);
				}
			}
			if ($found) {
				foreach ($found as $role => $folders) {
					if (isset($folders[0])) {
						// Set the first as default
						$aFolder = &$aResponse['Result']['@Collection'][$folders[0]];
						$this->Logger()->Write("Set {$role} mailbox to {$aFolder['fullName']}");
						$aFolder['role'] = $role;
					} else if ($this->Config()->Get('plugin', 'autocreate_system_folders', false)) {
						try
						{
							$sParent = \substr($aResponse['Result']['namespace'], 0, -1);
							$sFolderNameToCreate = \ucfirst($role);
/*
							$this->Manager()->RunHook('filter.folders-system-types', array($oAccount, &$aList));
							$iPos = \strrpos($sFolderNameToCreate, $sDelimiter);
							if (false !== $iPos) {
								$mNewParent = \substr($sFolderNameToCreate, 0, $iPos);
								$mNewFolderNameToCreate = \substr($sFolderNameToCreate, $iPos + 1);
								if (\strlen($mNewFolderNameToCreate)) {
									$sFolderNameToCreate = $mNewFolderNameToCreate;
								}

								if (\strlen($mNewParent)) {
									$sParent = \strlen($sParent) ? $sParent.$sDelimiter.$mNewParent : $mNewParent;
								}
							}
*/
							$this->Logger()->Write("Create {$role} mailbox {$sFolderNameToCreate}");
							$aFolder = $oActions->MailClient()->FolderCreate(
								$sFolderNameToCreate,
								$sParent,
								true,
								$sDelimiter
							)->jsonSerialize();
							$aFolder['role'] = $role;
							$aResponse['Result']['@Collection'][] = $aFolder;
						}
						catch (\Throwable $oException)
						{
							$this->Logger()->WriteException($oException);
						}
					} else {
						$this->Logger()->Write("Mailbox for {$role} not created");
					}
				}
			}
		}
	}

	/**
	 * @staticvar array $aCache
	 */
	private function systemFoldersNames(\RainLoop\Model\Account $oAccount) : array
	{
		static $aCache = null;
		if (null === $aCache) {
			$aCache = array(
				'Sent' => FolderType::SENT,
				'Send' => FolderType::SENT,
				'Outbox' => FolderType::SENT,
				'Out box' => FolderType::SENT,
				'Sent Item' => FolderType::SENT,
				'Sent Items' => FolderType::SENT,
				'Send Item' => FolderType::SENT,
				'Send Items' => FolderType::SENT,
				'Sent Mail' => FolderType::SENT,
				'Sent Mails' => FolderType::SENT,
				'Send Mail' => FolderType::SENT,
				'Send Mails' => FolderType::SENT,

				'Drafts' => FolderType::DRAFTS,
				'Draft' => FolderType::DRAFTS,
				'Draft Mail' => FolderType::DRAFTS,
				'Draft Mails' => FolderType::DRAFTS,
				'Drafts Mail' => FolderType::DRAFTS,
				'Drafts Mails' => FolderType::DRAFTS,

				'Junk' => FolderType::JUNK,
				'Junk E-mail' => FolderType::JUNK,
				'Spam' => FolderType::JUNK,
				'Spams' => FolderType::JUNK,
				'Bulk Mail' => FolderType::JUNK,
				'Bulk Mails' => FolderType::JUNK,

				'Trash' => FolderType::TRASH,
				'Deleted' => FolderType::TRASH,
				'Deleted Items' => FolderType::TRASH,
				'Bin' => FolderType::TRASH,

				'Archive' => FolderType::ARCHIVE,
				'Archives' => FolderType::ARCHIVE,

				'All' => FolderType::ALL,
				'All Mail' => FolderType::ALL,
				'All Mails' => FolderType::ALL,
			);

			$aNewCache = array();
			foreach ($aCache as $sKey => $iType) {
				$aNewCache[$sKey] = $iType;
				$aNewCache[\str_replace(' ', '', $sKey)] = $iType;
			}

			$aCache = $aNewCache;

			$this->Manager()->RunHook('filter.system-folders-names', array($oAccount, &$aCache));
		}

		return $aCache;
	}
}
