<?php
/**
 * Setup Class
 *
 * @version     1.0.$Revision:$
 * @version     SVN: $Id:$
 * @package     bplan-base/globals
 * @subpackage  Setup
 * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
 * @copyright   Copyright (C) 2025 bplan-solutions GmbH & Co. KG <https://www.bplan-solutions.de/>
 * /Δ\
 */

namespace BplanBase\Globals\Setup;


use Illuminate\Support\Facades\File;
use InvalidArgumentException;


/**
 * Setup Class
 *
 * @version     1.1.0 / 2025-07-22
 * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
 */
class FilePublisher
{


/* +++ TRAITS +++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */


/* +++ CLASS CONSTANTS +++ ++++++++++++++++++++++++++++++++++++++++++++++++++ */


    /**
     * @var     string STATUS_DONE
     */
    const STATUS_DONE    = 'DONE';


    /**
     * @var     string STATUS_MISSING
     */
    const STATUS_MISSING = 'MISSING';


    /**
     * @var     string STATUS_SKIPPED
     */
    const STATUS_SKIPPED = 'SKIPPED';


/* +++ OBJECT MEMBERS +++ +++++++++++++++++++++++++++++++++++++++++++++++++++ */


    /**
     * @var         string $_basePath
     */
    protected string $_basePath;


    /**
     * @var         null|callable $_callback
     */
    protected $_callback;


    /**
     * @var         array $_files
     */
    protected array $_files;


    /**
     * @var         bool $_force
     */
    protected bool $_force = false;


/* +++ CLASS MEMBERS +++ ++++++++++++++++++++++++++++++++++++++++++++++++++++ */


/* +++ OBJECT METHODS +++ +++++++++++++++++++++++++++++++++++++++++++++++++++ */


    /**
     *
     * @param       string $sourceBasePath
     *
     * @param       array $files
     *
     * @param       callable|null $callback
     *
     * @throws      InvalidArgumentException
     *
     * @version     1.0.1 / 2025-07-22
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public function __construct(string $sourceBasePath, array $files, null|callable $callback = null)
    {
        $sourceBasePath = str_replace('\\', '/', $sourceBasePath);

        if (!File::exists($sourceBasePath)) {
            throw new InvalidArgumentException('Path ['.$sourceBasePath.'] does not exist.');
        }
        if ($callback !== null && !is_callable($callback)) {
            throw new InvalidArgumentException('Invalid callable given.');
        }
        $this->_callback = $callback;
        $this->_basePath = $sourceBasePath;
        $this->_files = $files;

    } // __construct()


    /**
     *
     * @param       string $status
     *
     * @param       string $message
     *
     * @param       string $source
     *
     * @param       string $target
     *
     * @return      void
     *
     * @version     1.0.0 / 2025-06-19
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _emit(string $status, string $message, string $source = '', string $target = ''): void
    {
        if ($this->_callback !== null) {
            call_user_func($this->_callback, [
                'status' => $status,
                'message' => $message,
                'source' => $source,
                'target' => $target,
            ]);
        }
    } // _emit()


    /**
     *
     * @return      self
     *
     * @version     1.0.0 / 2025-06-19
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public function force(): self
    {
        $this->_force = true;

        return $this;

    } // force()


    /**
     *
     * @return      void
     *
     * @version     1.0.0 / 2025-06-19
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public function publish(): void
    {
        foreach ($this->_files as $source => $target) {
            $sourceFile = $this->_basePath.'/'.$source;
            $sourceFileName = basename($source);
            $targetFile = base_path($target);
            $targetPath = dirname($targetFile);

            if (!File::exists($sourceFile)) {
                $this->_emit(self::STATUS_MISSING, 'Missing source', $sourceFileName, $target);

                continue;
            }
            if ($this->_force === false && File::exists($targetFile)) {
                $this->_emit(self::STATUS_SKIPPED, 'Target exists', $sourceFileName, $target);

                continue;
            }
            File::ensureDirectoryExists($targetPath);
            File::copy($sourceFile, $targetFile);

            $this->_emit(self::STATUS_DONE, 'Copied', $sourceFileName, $target);
        }
    } // publish()


/* +++ CLASS METHODS +++ ++++++++++++++++++++++++++++++++++++++++++++++++++++ */


} // class FilePublisher {}
