<?php

use \GuzzleHttp\Client;

$app = $this->app;

return [
    'name' => 'pages',
    'icon' => 'pages:icon.svg',
    'fields' => [
        [
            'name' => 'pages',
            'type' => 'boolean',
        ],
        [
            'name' => 'menus',
            'type' => 'boolean',
        ],
        [
            'name' => 'settings',
            'type' => 'boolean',
        ]
    ],

    'sync:push' => function(array $settings = [], ?array $target = null, ?Client $client = null) {

        $settings = array_merge([
            'syncAll' => true,
            'pages' => false,
            'menus' => false,
            'settings' => false,
        ], $settings);

        extract($settings);

        if ($syncAll) {
            $pages = true;
            $menus = true;
            $settings = true;
        }

        if ($settings) {

            $payload = [
                'settings' => $this->module('pages')->settings()
            ];

            $client->request('POST', 'api/sync/job', [
                'json' => [
                    'job' => 'pages',
                    'mode' => 'push',
                    'payload' => $this->helper('jwt')->encode($payload, $target['syncKey'])
                ]
            ]);
        }

        if ($menus) {

            $payload = [
                'menus' => $this->dataStorage->find('pages/menus')->toArray()
            ];

            $client->request('POST', 'api/sync/job', [
                'json' => [
                    'job' => 'pages',
                    'mode' => 'push',
                    'payload' => $this->helper('jwt')->encode($payload, $target['syncKey'])
                ]
            ]);
        }

        if ($pages) {

            $run = 0;
            $limit = 20;

            while (true) {

                $_pages = $this->dataStorage->find('pages', [
                    'skip' => $run * $limit,
                    'limit' => $limit
                ])->toArray();

                $payload = [
                    'run' => $run,
                    'pages' => $_pages
                ];

                if (count($_pages)) {

                    $client->request('POST', 'api/sync/job', [
                        'json' => [
                            'job' => 'pages',
                            'mode' => 'push',
                            'payload' => $this->helper('jwt')->encode($payload, $target['syncKey'])
                        ]
                    ]);
                }

                if (!count($_pages)) {
                    break;
                }

                $run += 1;
            };
        }
    },

    'on:push' => function($payload = null) {

        if (isset($payload['settings'])) {
            $settings = $payload['settings'];
            $this->trigger('pages.settings.save', [&$settings]);
            $this->dataStorage->setKey('pages/options', 'settings', $settings);
        }

        if (isset($payload['menus'])) {

            foreach ($payload['menus'] as $menu) {
                $this->dataStorage->remove('pages/menus', ['_id' => $menu['_id']]);
                $this->dataStorage->insert('pages/menus', $menu);
            }
        }

        if (isset($payload['pages'])) {

            if (isset($payload['run']) && $payload['run'] === 0) {
                $this->dataStorage->dropCollection('pages');
            }

            foreach ($payload['pages'] as $page) {
                $this->dataStorage->insert('pages', $page);
            }
        }

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

    'sync:pull' => function(array $settings = [], ?array $target = null, ?Client $client = null) {

        $settings = array_merge([
            'syncAll' => true,
            'pages' => false,
            'menus' => false,
            'settings' => false,
        ], $settings);

        extract($settings);

        if ($syncAll) {
            $pages = true;
            $menus = true;
            $settings = true;
        }

        if ($settings) {

            $response = $client->request('POST', 'api/sync/job', [
                'json' => [
                    'job' => 'pages',
                    'mode' => 'pull',
                    'payload' => $this->helper('jwt')->encode([
                        'settings' => true
                    ], $target['syncKey'])
                ]
            ]);

            $payload = json_decode($response->getBody()->getContents(), true);

            if (isset($payload['settings'])) {
                $settings = $payload['settings'];
                $this->trigger('pages.settings.save', [&$settings]);
                $this->dataStorage->setKey('pages/options', 'settings', $settings);
            }
        }

        if ($menus) {

            $response = $client->request('POST', 'api/sync/job', [
                'json' => [
                    'job' => 'pages',
                    'mode' => 'pull',
                    'payload' => $this->helper('jwt')->encode([
                        'menus' => true
                    ], $target['syncKey'])
                ]
            ]);

            $payload = json_decode($response->getBody()->getContents(), true);

            if (isset($payload['menus'])) {
                foreach ($payload['menus'] as $menu) {
                    $this->dataStorage->remove('pages/menus', ['_id' => $menu['_id']]);
                    $this->dataStorage->insert('pages/menus', $menu);
                }
            }
        }

        if ($pages) {

            $run = 0;
            $this->dataStorage->dropCollection('pages');

            while (true) {

                $response = $client->request('POST', 'api/sync/job', [
                    'json' => [
                        'job' => 'pages',
                        'mode' => 'pull',
                        'payload' => $this->helper('jwt')->encode([
                            'pages' => true,
                            'run' => $run
                        ], $target['syncKey'])
                    ]
                ]);

                $payload = json_decode($response->getBody()->getContents(), true);

                if (!isset($payload['pages']) || !count($payload['pages'])) {
                    break;
                }

                foreach ($payload['pages'] as $page) {
                    $this->dataStorage->insert('pages', $page);
                }

                $run += 1;
            }
        }
    },

    'on:pull' => function($payload = null) {

        if (isset($payload['settings']) && $payload['settings']) {
            return ['settings' => $this->module('pages')->settings()];
        }

        if (isset($payload['menus']) && $payload['menus']) {
            return ['menus' => $this->dataStorage->find('pages/menus')->toArray()];
        }

        if (isset($payload['pages']) && $payload['pages']) {

            $run = $payload['run'] ?? 0;
            $limit = 20;

            $pages = $this->dataStorage->find('pages', [
                'skip' => $run * $limit,
                'limit' => $limit
            ])->toArray();

            return ['pages' => $pages];
        }

        return ['success' => false];
    },

    'sync:push:item' => function(array $payload, ?array $target = null, ?Client $client = null) {

        $payload['item'] = $this->dataStorage->findOne('pages', ['_id' => $payload['item']['_id']]);

        $response = $client->request('POST', 'api/sync/item', [
            'json' => [
                'job' => 'pages',
                'mode' => 'push',
                'payload' => $this->helper('jwt')->encode($payload, $target['syncKey'])
            ]
        ]);

        if (isset($payload['syncAssets']) && $payload['syncAssets']) {

            $assets = $this->helper('sync')->getLinkedAssets($payload['item']);

            if (count($assets)) {

                $client->request('POST', 'api/sync/job', [
                    'json' => [
                        'job' => 'assets',
                        'mode' => 'push',
                        'payload' => $this->helper('jwt')->encode([
                            'run' => 0,
                            'uploads' => $this->fileStorage->getURL('uploads://'),
                            'assets' => $assets
                        ], $target['syncKey'])
                    ]
                ]);
            }
    }

        $response = json_decode($response->getBody()->getContents(), true);

        return $response;
    },

    'on:push:item' => function(array $payload) {

        if (!isset($payload['item'])) {
            return ['success' => false];
        }

        if (isset($payload['item']['_pid']) && $payload['item']['_pid']) {

            $parent = $this->dataStorage->findOne('pages', ['_id' => $payload['item']['_pid']]);

            if (!$parent) {
                return ['success' => false, 'message' => 'Parent does not exist'];
            }
        }

        $this->dataStorage->remove('pages', ['_id' => $payload['item']['_id']]);
        $this->dataStorage->insert('pages', $payload['item']);

        $this->helper('pages')->updateRoutes($payload['item']['_id']);

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

    'sync:pull:item' => function(array $payload, ?array $target = null, ?Client $client = null) {

        $response = $client->request('POST', 'api/sync/item', [
            'json' => [
                'job' => 'pages',
                'mode' => 'pull',
                'payload' => $this->helper('jwt')->encode($payload, $target['syncKey'])
            ]
        ]);

        $response = json_decode($response->getBody()->getContents(), true);

        if (!isset($response['item'])) {
            return ['success' => false, 'message' => 'Item not found'];
        }

        if (isset($response['item']['_pid']) && $response['item']['_pid']) {

            $parent = $this->dataStorage->findOne('pages', ['_id' => $response['item']['_pid']]);

            if (!$parent) {
                return ['success' => false, 'message' => 'Parent does not exist'];
            }
        }

        $this->dataStorage->remove('pages', ['_id' => $response['item']['_id']]);
        $this->dataStorage->insert('pages', $response['item']);

        $this->helper('pages')->updateRoutes($response['item']['_id']);

        if (isset($payload['syncAssets']) && $response['item']) {

            $assets = $this->helper('sync')->getLinkedAssets($response['item']);

            $streamContext = stream_context_create( [
                'ssl' => [
                    'verify_peer' => false,
                    'verify_peer_name' => false,
                ],
            ]);

            foreach ($assets as $asset) {

                $path = trim($asset['path'], '/');
                $url = "{$response['uploads']}/{$path}";

                if (!$this->fileStorage->fileExists("uploads://{$path}")) {

                    // check if resource exists
                    $headers = get_headers($url, 1, $streamContext);

                    if ($headers === false || !str_contains($headers[0], ' 200')) {
                        continue;
                    }

                    $stream = fopen($url, 'rb', false, $streamContext);

                    if ($stream === false) {
                        continue;
                    }

                    $this->fileStorage->writeStream("uploads://{$path}", $stream, ['mimetype' => $asset['mime']]);

                    if (is_resource($stream)) {
                        fclose($stream);
                    }
                }

                $this->dataStorage->remove('assets', ['_id' => $asset['_id']]);
                $this->dataStorage->insert('assets', $asset);
            }
        }


        return ['success' => true, 'item' => $response['item']];

    },

    'on:pull:item' => function(array $payload) {

        $item = $this->dataStorage->findOne('pages', ['_id' => $payload['item']['_id']]);

        return ['item' => $item, 'uploads' => $this->fileStorage->getURL('uploads://')];
    },

];
