<?php

// Register Helpers
$this->helpers['sync'] = 'Sync\\Helper\\Sync';

// load admin related code
$this->on('app.admin.init', function() {
    include(__DIR__.'/admin.php');
});

// register sync api endpoint
$this->on('app.api.request', function($request) {

    if (!in_array($request->route, ['/api/sync/check', '/api/sync/job', '/api/sync/item', '/api/sync/finished'])) {
        return;
    }

    $this->helper('session')->close();

    $this->bind('/api/sync/check', function() {
        return ['success' => true];
    });

    $this->bind('/api/sync/job', function($params) {

        $jobName = $this->param('job');
        $mode = $this->param('mode');
        $payload = $this->param('payload');

        if (!isset($jobName, $mode, $payload) || !in_array($mode, ['pull', 'push'])) {
            return $this->stop(['error' => 'Unknown sync mode'], 412);
        }

        try {
            $payload = $this->helper('jwt')->decode($payload, $this->module('sync')->syncKey());
            $payload = json_decode(json_encode($payload), true);
        } catch(\Throwable $e) {
            return $this->stop(['error' => 'Decoding payload failed'], 412);
        }

        $job = $this->module('sync')->jobs($jobName);

        if (!$job) {
            return $this->stop(['error' => "Unknown job <<{$jobName}>>"], 412);
        }

        $callback = Closure::bind($job["on:{$mode}"], $this, $this);

        return $callback($payload);
    });

    $this->bind('/api/sync/item', function($params) {

        $jobName = $this->param('job');
        $mode = $this->param('mode');
        $payload = $this->param('payload');

        if (!isset($jobName, $mode, $payload) || !in_array($mode, ['pull', 'push'])) {
            return $this->stop(['error' => 'Unknown sync mode'], 412);
        }

        try {
            $payload = $this->helper('jwt')->decode($payload, $this->module('sync')->syncKey());
            $payload = json_decode(json_encode($payload), true);
        } catch(\Throwable $e) {
            return $this->stop(['error' => 'Decoding payload failed'], 412);
        }

        $job = $this->module('sync')->jobs($jobName);

        if (!$job) {
            return $this->stop(['error' => "Unknown job <<{$jobName}>>"], 412);
        }

        if (!isset($job["on:{$mode}:item"])) {
            return $this->stop(['error' => "Missing sync handler on:{$mode}:item"], 412);
        }

        $callback = Closure::bind($job["on:{$mode}:item"], $this, $this);

        return $callback($payload);
    });

    $this->bind('/api/sync/finished', function($params) {

        $payload = $this->param('payload');

        try {
            $payload = $this->helper('jwt')->decode($payload, $this->module('sync')->syncKey());
            $payload = json_decode(json_encode($payload), true);
        } catch(\Throwable $e) {
            return $this->stop(['error' => 'Decoding payload failed'], 412);
        }

        if (!isset($payload['target'], $payload['jobs'])) {
            return $this->stop(['error' => 'False payload'], 412);
        }

        $this->trigger("sync.target.{$payload['target']['mode']}.finished", [$payload['target'], $payload['jobs']]);

        return ['success' => true];
    });
});

// sync api
$this->module('sync')->extend([

    'syncKey' => function() {
        return $this->app->retrieve('sync/syncKey', null);
    },

    'jobs' => function(?string $job = null) {

        static $jobs;

        if (!$jobs) {

            $jobs = new ArrayObject([]);

            if ($this->app->module('assets')) {
                $jobs['assets'] = include(__DIR__.'/SyncJobs/assets/config.php');
            }

            if ($this->app->module('content')) {
                $jobs['content'] = include(__DIR__.'/SyncJobs/content/config.php');
            }

            if ($this->app->module('pages')) {
                $jobs['pages'] = include(__DIR__.'/SyncJobs/pages/config.php');
            }

            if ($this->app->module('layout')) {
                $jobs['layout'] = include(__DIR__.'/SyncJobs/layout/config.php');
            }

            if ($this->app->module('lokalize')) {
                $jobs['lokalize'] = include(__DIR__.'/SyncJobs/lokalize/config.php');
            }

            $jobs['system:roles'] = include(__DIR__.'/SyncJobs/system/roles.php');

            $this->app->trigger('sync.jobs', [$jobs]);
        }

        return $job ? ($jobs[$job] ?? null) : $jobs;

    }
]);
