<?php

/**
 *
 * bareos-webui - Bareos Web-Frontend
 *
 * @link      https://github.com/bareos/bareos for the canonical source repository
 * @copyright Copyright (C) 2013-2026 Bareos GmbH & Co. KG (http://www.bareos.org/)
 * @license   GNU Affero General Public License (http://www.gnu.org/licenses/)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

namespace Restore\Model;

class RestoreModel
{
    /**
     * Get Directories via .bvfs_lsdirs
     *
     * @param $bsock
     * @param $jobid
     * @param $pathid
     *
     * @return array
     */
    public function getDirectories(&$bsock = null, $jobid = null, $pathid = null): array
    {
        if (isset($bsock)) {
            $limit = 1000;
            $offset = 0;
            $retval = array();

            while (true) {
                if ($pathid == null || $pathid == "#") {
                    $cmd_1 = '.bvfs_lsdirs jobid=' . $jobid . ' path= limit=' . $limit . ' offset=' . $offset;
                } else {
                    $cmd_1 = '.bvfs_lsdirs jobid=' . $jobid . ' pathid=' . abs($pathid) . ' limit=' . $limit . ' offset=' . $offset;
                }
                $result = $bsock->send_command($cmd_1, 2);
                $directories = \Laminas\Json\Json::decode($result, \Laminas\Json\Json::TYPE_ARRAY);
                if (empty($directories['result'])) {
                    $cmd_2 = '.bvfs_lsdirs jobid=' . $jobid . ' path=@ limit=' . $limit;
                    $result = $bsock->send_command($cmd_2, 2);
                    $directories = \Laminas\Json\Json::decode($result, \Laminas\Json\Json::TYPE_ARRAY);
                    if (empty($directories['result'])) {
                        return $retval;
                    }
                    if (count($directories['result']['directories']) <= 2) {
                        $retval = array_merge($retval, $directories['result']['directories']);
                        // as . and .. are always returned, filter possible duplicates of . and .. (current and parent dir)
                        foreach ($retval as $key => $value) {
                            if ($retval[$key]['name'] === "." || $retval[$key]['name'] === "..") {
                                unset($retval[$key]);
                            }
                        }
                        return $retval;
                    } else {
                        $retval = array_merge($retval, $directories['result']['directories']);
                    }
                }
                // no more results?
                elseif (count($directories['result']['directories']) <= 2) {
                    $retval = array_merge($retval, $directories['result']['directories']);
                    // as . and .. are always returned, filter possible duplicates of . and .. (current and parent dir)
                    foreach ($retval as $key => $value) {
                        if ($retval[$key]['name'] === "." || $retval[$key]['name'] === "..") {
                            unset($retval[$key]);
                        }
                    }
                    return $retval;
                }
                // continue
                else {
                    $retval = array_merge($retval, $directories['result']['directories']);
                }
                $offset = $offset + $limit;
            }
        } else {
            throw new \Exception('Missing argument.');
        }
    }

    /**
     * Get Files via .bvfs_lsfiles
     *
     * @param $bsock
     * @param $jobid
     * @param $pathid
     *
     * @return array
     */
    public function getFiles(&$bsock = null, $jobid = null, $pathid = null): array
    {
        if (isset($bsock)) {
            $limit = 1000;
            $offset = 0;
            $retval = array();

            while (true) {
                if ($pathid == null || $pathid == "#") {
                    $cmd_1 = '.bvfs_lsfiles jobid=' . $jobid . ' path= limit=' . $limit . ' offset=' . $offset;
                } else {
                    $cmd_1 = '.bvfs_lsfiles jobid=' . $jobid . ' pathid=' . abs($pathid) . ' limit=' . $limit . ' offset=' . $offset;
                }
                $result = $bsock->send_command($cmd_1, 2);
                $files = \Laminas\Json\Json::decode($result, \Laminas\Json\Json::TYPE_ARRAY);
                if (empty($files['result'])) {
                    return $retval;
                }
                if (empty($files['result']['files'])) {
                    $cmd_2 = '.bvfs_lsfiles jobid=' . $jobid . ' path=@ limit=' . $limit . ' offset=' . $offset;
                    $result = $bsock->send_command($cmd_2, 2);
                    $files = \Laminas\Json\Json::decode($result, \Laminas\Json\Json::TYPE_ARRAY);
                    if (empty($files['result']['files'])) {
                        return $retval;
                    } else {
                        $retval = array_merge($retval, $files['result']['files']);
                    }
                } else {
                    $retval = array_merge($retval, $files['result']['files']);
                }
                $offset = $offset + $limit;
            }
        } else {
            throw new \Exception('Missing argument.');
        }
    }

    /**
     * Get Versions via .bvfs_versions
     *
     * @param $bsock
     * @param $clientname
     * @param $pathid
     * @param $filename
     *
     * @return array
     */
    public function getFileVersions(&$bsock = null, $clientname = null, $pathid = null, $filename = null): ?array
    {
        if (isset($bsock)) {
            $cmd = '.bvfs_versions jobid=0 client=' . $clientname . ' pathid=' . $pathid . ' fname="' . addslashes($filename) . '"';
            $result = $bsock->send_command($cmd, 2);
            try {
                $versions = \Laminas\Json\Json::decode($result, \Laminas\Json\Json::TYPE_ARRAY);
            } catch (\Throwable $e) {
                error_log('getFileVersions: failed to decode response');
                return null;
            }

            if (
                !is_array($versions)
                || !isset($versions['result'])
                || !array_key_exists('versions', $versions['result'])
                || !is_array($versions['result']['versions'])
            ) {
                error_log('getFileVersions: missing result versions');
                return null;
            }

            return $versions['result']['versions'];
        } else {
            throw new \Exception('Missing argument.');
        }
    }

    /**
     * Get all configured restore job resources
     *
     * @param $bsock
     * @param $restorejobs
     *
     * @return array
     */
    public function getRestoreJobResources(&$bsock = null, $restorejobs = null): array
    {
        if (isset($bsock) && isset($restorejobs)) {
            $restorejobresources = array();
            foreach ($restorejobs as $restorejob) {
                $job = $restorejob['name'];
                $cmd = '.defaults job="' . $job . '"';
                $result = $bsock->call_json($cmd);
                $defaults = $result['defaults'];
                if (!empty($defaults)) {
                    $restorejobresources[$job] = $defaults;
                }
            }
            return $restorejobresources;
        } else {
            throw new \Exception('Missing argument.');
        }
    }

    /**
     * Get JobIds via .bvfs_get_jodids
     *
     * @param $bsock
     * @param $jobid
     * @param $mergefilesets
     * @param $mergejobs
     *
     * @return array
     */
    public function getJobIds(&$bsock = null, $jobid = null, $mergefilesets = 1, $mergejobs = 1)
    {
        if (isset($bsock) && isset($jobid)) {
            if ($mergejobs == 0) {
                return $jobid;
            }
            if ($mergefilesets == 1) {
                $cmd = '.bvfs_get_jobids jobid=' . $jobid . ' all';
            } else {
                $cmd = '.bvfs_get_jobids jobid=' . $jobid;
            }
            $result = $bsock->send_command($cmd, 2);
            $jobids = \Laminas\Json\Json::decode($result, \Laminas\Json\Json::TYPE_ARRAY);
            $result = "";
            if (isset($jobids['result']['jobids'])) {
                $i = count($jobids['result']['jobids']);
                foreach ($jobids['result']['jobids'] as $jobid) {
                    $result .= $jobid['id'];
                    --$i;
                    if ($i > 0) {
                        $result .= ",";
                    }
                }
            }
            return $result;
        } else {
            throw new \Exception('Missing argument.');
        }
    }

    /**
     * Updates the bvfs cache
     *
     * @param $bsock
     * @param $jobid
     */
    public function updateBvfsCache(&$bsock = null, $jobid = null): void
    {
        if (isset($bsock)) {
            if ($jobid != null) {
                $cmd = '.bvfs_update jobid=' . $jobid;
            } else {
                $cmd = '.bvfs_update';
            }
            $result = $bsock->send_command($cmd, 2);
        } else {
            throw new \Exception('Missing argument.');
        }
    }

    /**
     * Restore
     *
     * @param $bsock
     * @param $jobid
     * @param $client
     * @param $restoreclient
     * @param $restorejob
     * @param $where
     * @param $fileid
     * @param $dirid
     * @param $jobids
     * @param $replace
     * @param $pluginoptions
     *
     * @return string
     */
    public function restore(&$bsock = null, $jobid = null, $client = null, $restoreclient = null, $restorejob = null, $where = null, $fileid = null, $dirid = null, $jobids = null, $replace = null, $pluginoptions = null): string
    {
        if (isset($bsock)) {
            $result = $bsock->restore($jobid, $client, $restoreclient, $restorejob, $where, $fileid, $dirid, $jobids, $replace, $pluginoptions);
            return $result;
        } else {
            throw new \Exception('Missing argument');
        }
    }

    public function isNDMPBackupClient(&$bsock = null, $client = null): ?bool
    {
        if (!isset($bsock)) {
            throw new \Exception('Missing argument');
        }

        if ($client != null) {
            $cmd = 'show client=' . $client;
            $result = $bsock->send_command($cmd, 0);
            $keywords = array('NDMPv2', 'NDMPv3', 'NDMPv4');
            foreach ($keywords as $keyword) {
                if (stripos($result, $keyword) !== false) {
                    return true;
                }
            }
            return false;
        }

        throw new \Exception('Missing argument');
    }
}
