<?php

include(__DIR__.'/events.php');

// Register CLI commands
$this->on('app.cli.init', function($cli) {
    $app = $this;
    include(__DIR__.'/cli.php');
});

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

    // memoize data
    '_idxTypes' => null,
    '_runnerState' => null,

    'indexTypes' => function(?string $type = null) {

        if (!isset($this->props['_idxTypes'])) {

            $app = $this->app;

            $include = function($file) use ($app) {
                return include($file);
            };

            $types = new ArrayObject([
                'index' => $include(__DIR__.'/IndexTypes/index/config.php')
            ]);

            if ($this->app->module('content')) {
                $types['content:collection'] = $include(__DIR__.'/IndexTypes/content/config.php');
            }

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

            $this->props['_idxTypes'] = $types;

            $this->app->trigger('detektivo.collect.indextypes', [$types, $include]);
        }

        return $type ? ($this->props['_idxTypes'][$type] ?? null) : $this->props['_idxTypes'];
    },

    'createIndex' => function(string $name, array $data = []): mixed {

        if (!trim($name) || $this->exists($name)) {
            return false;
        }

        $index = array_replace_recursive([
            'name'      => $name,
            'label'     => $name,
            'info'      => '',
            'type'      => 'index',
            'fields'    => [],
            'group'     => null,
            'meta'      => null,
            '_created'  => time(),
        ], $data);

        if (!is_array($index['fields']) || !count($index['fields'])) {
            return false;
        }

        $export = $this->app->helper('utils')->var_export($index, true);

        if (!$this->app->helper('fs')->write("#storage:detektivo/{$name}.index.php", "<?php\n return {$export};")) {
            return false;
        }

        $this->app->search->createIndex("detektivo.{$name}", $index['fields']);

        return $index;
    },

    'removeIndex' => function(string $name): bool {

        if (!$this->exists($name)) {
            return false;
        }

        $this->app->helper('fs')->delete("#storage:detektivo/{$name}.index.php");
        $this->app->search->removeIndex("detektivo.{$name}");

        $this->app->trigger('detektivo.remove.index', [$name]);

        return true;
    },

    'exists' => function(string $name): ?string {
        return $this->app->path("#storage:detektivo/{$name}.index.php");
    },

    'index' => function(string $name, bool $indexCheck = false): mixed {

        if (!$this->exists($name)) {
            return null;
        }

        if ($indexCheck && !$this->app->search->exists("detektivo.{$name}")) {
            $this->app->search->createIndex("detektivo.{$name}", $this->indexes($name)['fields']);
        }

        return $this->app->search->index("detektivo.{$name}");
    },

    'indexes' => function(?string $name = null): ?array {

        $indexes = [];

        foreach ($this->app->helper('fs')->ls('*.index.php', '#storage:detektivo') as $file) {

            $store = include($file->getPathName());

            $indexes[$store['name']] = $store;
        }

        return $name ? ($indexes[$name] ?? null) : $indexes;
    },

    // indexer related methods

    'runnerState' => function(): \Detektivo\Helper\RunnerState {

        if (!isset($this->props['_runnerState'])) {
            $this->props['_runnerState'] = new \Detektivo\Helper\RunnerState($this->app);
        }

        return $this->props['_runnerState'];
    },

    'indexerHealthConfig' => function(): array {
        return $this->runnerState()->indexerHealthConfig();
    },

    'normalizeIndexerState' => function($name, ?array $state = null): array {
        return $this->runnerState()->normalizeIndexerState($name, $state);
    },

    'getIndexerState' => function($name): array {
        return $this->runnerState()->getIndexerState($name);
    },

    'setIndexerState' => function($name, string $status, array $meta = []): array {
        return $this->runnerState()->setIndexerState($name, $status, $meta);
    },

    'queueIndexer' => function($name): string|false {
        return $this->runnerState()->queueIndexer($name);
    },

    'beginIndexer' => function($name, array $meta = []): bool {
        return $this->runnerState()->beginIndexer($name, $meta);
    },

    'touchIndexer' => function($name, array $meta = []): array {
        return $this->runnerState()->touchIndexer($name, $meta);
    },

    'finishIndexer' => function($name, string $status = 'finished', array $meta = []): array {
        return $this->runnerState()->finishIndexer($name, $status, $meta);
    },

    'stopIndexer' => function($name): bool {
        return $this->runnerState()->stopIndexer($name);
    },

    'runIndexer' => function($name, $meta = []) {

        $index = $this->indexes($name);
        $runId = (isset($meta['_runId']) && \is_string($meta['_runId'])) ? $meta['_runId'] : null;

        if (!$index) {
            $this->finishIndexer($name, 'failed', ['error' => 'Index not found']);
            return false;
        }

        $type = $this->indexTypes($index['type']);

        if (!$type || !isset($type['index'])) {
            if (!$this->beginIndexer($name, ['runId' => $runId])) {
                return false;
            }
            $this->finishIndexer($name, 'finished');
            return true;
        }

        $indexer = new \Detektivo\Helper\Indexer($name, $this->app);

        try {
            return (bool) $indexer->start($meta);
        } catch (\Throwable $e) {
            return false;
        }
    },

    'isIndexerRunning' => function($name) {
        return $this->runnerState()->isIndexerRunning($name);
    },

    'getIndexerLog' => function($name) {
        return $this->runnerState()->getIndexerLog($name);
    },
]);
