<?php
/**
 * BookiFlex Core
 *
 * @package    BookiFlex
 * @subpackage Core
 * @author     BookiFlex
 * @copyright  Copyright (c) 2025 BookiFlex
 * @license    GPL-2.0-or-later
 *
 * @link       https://bookiflex.com
 */

declare(strict_types=1);

namespace BookiFlex\Core\Repository;

use BookiFlex\Core\ORM\DataProvider\CustomPostTypeDataProvider;
use Cycle\ORM\Iterator;
use Cycle\ORM\ORM;
use Cycle\ORM\Select;
use Cycle\ORM\Select\Repository;
use BookiFlex\Core\Util\Str;

defined( 'ABSPATH' ) || exit;

/**
 * Base class for custom post type repositories.
 */
abstract class BaseCPTRepository extends Repository
{
    protected ORM $orm;
    protected CustomPostTypeDataProvider $provider;

    protected static string $postType = '';
    protected static string $class    = '';

    public function __construct(Select $select, ORM $orm, CustomPostTypeDataProvider $provider)
    {
        parent::__construct($select);
        $this->orm      = $orm;
        $this->provider = $provider;
    }

    public function findByPK($id): ?object
    {
        $object = $this->findInHeap(['id' => $id]);
        if ($object !== null) {
            return $object;
        }

        $data = $this->provider->getData(static::$postType, [$id], false);
        if (empty($data)) {
            return null;
        }
        $iterator = Iterator::createWithOrm($this->orm, static::$class, $data, false, true);

        return $iterator->getIterator()->current();
    }

    public function findOne(array $scope = []): ?object
    {
        $id = $scope['id'] ?? null;
        if ($id === null) {
            return null;
        }

        $object = $this->findInHeap(['id' => $id]);
        if ($object !== null) {
            return $object;
        }

        $data = $this->provider->getData(static::$postType, [$id]);
        if (empty($data)) {
            return null;
        }

        $iterator = Iterator::createWithOrm($this->orm, static::$class, $data, false, true);

        return $iterator->getIterator()->current();
    }

    public function findAll(array $scope = [], array $orderBy = []): iterable
    {;
        $data = $this->findRawData($scope, $orderBy);
//        var_dump($data);
        try {
            return Iterator::createWithOrm($this->orm, static::$class, $data, false, true);
        } catch (\Throwable $e) {
            unset($e);
        }

		return [];
    }

    protected function findRawData(array $scope = [], array $orderBy = []): array
    {
        $data = $this->provider->getData(
            static::$postType,
            $scope['ids']        ?? [],
            $scope['onlyActive'] ?? false
        );

        if ($data === null) {
            return [];
        }

        return $data;
    }

    protected function findInHeap(array $scope): ?object
    {
        $role = Str::snakeToCamel(static::$postType);
        $heap = $this->orm->getHeap();

        return $heap->find($role, $scope);
    }
}
