<?php

include_once __DIR__ . '/export/autoload.php';
include_once __DIR__ . '/import/autoload.php';

/**
 * Class DataTransfer_model
 */
class Data_transfer_model extends Cf_Model
{
    private $isAdmin;
    private $controlPhrase = ['file' => 'controlPhrase.txt', 'content' => 'Control phrase to check encryption key!'];
    private $pharObject;
    private $archiveName;
    private $userCategories = [
        ['id' => 'categorizations', 'name' => 'Host categorizations'],
        ['id' => 'dashboards', 'name' => 'Dashboards'],
        ['id' => 'reports', 'name' => 'Reports'],
    ];

    private $adminCategories = [
        ['id' => 'settingsScripts', 'name' => 'Custom notification scripts'],
        ['id' => 'users', 'name' => 'Users'],
        ['id' => 'settingsRoles', 'name' => 'Roles'],
        ['id' => 'settingsPreferences', 'name' => 'Preferences'],
        ['id' => 'settingsAuthentication', 'name' => 'LDAP authentication settings'],
        ['id' => 'settingsMail', 'name' => 'Mail settings'],
        ['id' => 'settingsVCS', 'name' => 'Version control repository'],
    ];

    public function setIsAdmin($value)
    {
        $this->isAdmin = $value;
    }

    public function getCategories()
    {
        if ($this->isAdmin) {
            $categories = array_merge($this->userCategories, $this->adminCategories);
        } else {
            $categories = $this->userCategories;
        }
        return $categories;
    }

    private function initializePharObject()
    {
        $this->load->helper('string');
        $now = DateTime::createFromFormat('U.u', microtime(true));
        $archiveName = 'export_' . $now->format('m-d-Y_H:i:s.u') . random_string('alnum', 32) . '.phar';
        $this->archiveName = str_replace(' ', '_', $archiveName);
        $this->pharObject = new Phar(get_tmpdir() . "$archiveName");
    }

    public function getExportCategories()
    {
        return $this->getCategories();
    }

    public function export($data)
    {
        $result = [];
        if (sizeof($data['items']) > 0) {
            $this->initializePharObject();
            $exportDataFactory = new ExportDataFactory();
            foreach ($data['items'] as $type) {
                /**
                 * @var $exporter BaseDataExporter
                 */
                $exporter = $exportDataFactory::createExporter($type);

                if ($exporter->isOnlyForAdmin() && $this->isAdmin === false) {
                    throw new Exception(
                        "Access denied. Your role does not have sufficient privileges to export $type.",
                    );
                }

                $exportResult = $exporter
                    ->setUsername($data['username'])
                    ->setEncryptionKey($data['encryptionKey'])
                    ->setIsAdmin($this->isAdmin)
                    ->setDbInstance($this->db)
                    ->setSettingsDbInstance($this->load->database('cfsettings', true))
                    ->setPharObject($this->pharObject)
                    ->setExportOnlyUserItems($data['exportOnlyUserItems'] === 'true' ? true : false)
                    ->getData();
                $result[$type] = $exportResult['info'];
                $this->pharObject->addFromString($type, $exportResult['data']);
            }
        }

        $this->pharObject->addFromString('export.json', json_encode($result));
        $this->pharObject->addFromString(
            $this->controlPhrase['file'],
            $this->cf_encrypt->encryptByKey($this->controlPhrase['content'], $data['encryptionKey']),
        );

        return $this->archiveName;
    }

    public function analyzeImport($data)
    {
        $result = [];
        $categories = $this->getCategories();
        foreach ($data as $key => $value) {
            if (in_array($key, array_column($categories, 'id'))) {
                $result[$key] = $value;
            }
        }
        return $result;
    }

    public function import(Phar $phar, $input)
    {
        $importDataFactory = new ImportDataFactory();

        $data = json_decode($phar['export.json']->getContent(), JSON_OBJECT_AS_ARRAY);

        foreach ($data as $type => $value) {
            /**
             * @var $importer BaseDataImporter
             */
            $importer = $importDataFactory::createImporter($type);

            if ($importer->isOnlyForAdmin() && $this->isAdmin === false) {
                throw new Exception("Access denied. Your role does not have sufficient privileges to import $type.");
            }

            $importer
                ->setUsername($input['username'])
                ->setEncryptionKey($input['encryptionKey'])
                ->setIsAdmin($this->isAdmin)
                ->setDbInstance($this->db)
                ->setSettingsDbInstance($this->load->database('cfsettings', true))
                ->setPharObject($phar)
                ->setSkipDuplicates((int) $input['skipDuplicates'])
                ->import($phar[$type]->getContent());
        }
    }

    public function validateEncryptionKey(Phar $phar, $key)
    {
        return $this->cf_encrypt->decryptByKey($phar[$this->controlPhrase['file']]->getContent(), $key) ==
            $this->controlPhrase['content'];
    }
}
