<?php
/***********************************************************************************
 * The contents of this file are subject to the Extension License Agreement
 * ("Agreement") which can be viewed at
 * https://www.espocrm.com/extension-license-agreement/.
 * By copying, installing downloading, or using this file, You have unconditionally
 * agreed to the terms and conditions of the Agreement, and You may not use this
 * file except in compliance with the Agreement. Under the terms of the Agreement,
 * You shall not license, sublicense, sell, resell, rent, lease, lend, distribute,
 * redistribute, market, publish, commercialize, or otherwise transfer rights or
 * usage to the software or any modified version or derivative work of the software
 * created by or for you.
 *
 * Copyright (C) 2015-2025 Letrium Ltd.
 *
 * License ID: e4c270586a0c8a9fda53bda910f357e0
 ************************************************************************************/

namespace Espo\Modules\Advanced\Core\ORM;

use Espo\ORM\Collection;
use Espo\ORM\Entity;
use Espo\ORM\EntityManager;

use PDOStatement;
use PDO;
use IteratorAggregate;
use stdClass;
use Traversable;

/**
 * @implements IteratorAggregate<int, Entity>
 * @implements Collection<Entity>
 */
class SthCollection implements IteratorAggregate, Collection
{
    /**
     * @param array<string, array<string, mixed>> $fieldDefs
     * @param string[] $linkMultipleFieldList
     * @param stdClass[] $foreignLinkFieldDataList
     */
    public function __construct(
        private PDOStatement $sth,
        private string $entityType,
        private EntityManager $entityManager,
        private $fieldDefs,
        private $linkMultipleFieldList,
        private $foreignLinkFieldDataList,
        private CustomEntityFactory $customEntityFactory
    ) {}

    public function getIterator(): Traversable
    {
        return (function () {
            while ($row = $this->sth->fetch(PDO::FETCH_ASSOC)) {

                $rowData = [];

                foreach ($row as $attr => $value) {
                    /** @var string $attribute */
                    $attribute = str_replace('.', '_', $attr);

                    $rowData[$attribute] = $value;
                }

                $entity = $this->customEntityFactory->create($this->entityType, $this->fieldDefs);

                $entity->set($rowData);
                $entity->setAsFetched();

                foreach ($this->linkMultipleFieldList as $field) {
                    $entity->loadLinkMultipleField($field);
                }

                foreach ($this->foreignLinkFieldDataList as $item) {
                    $foreignId = $entity->get($item->name . 'Id');

                    if ($foreignId) {
                        $foreignEntity = $this->entityManager
                            ->getRDBRepository($item->entityType)
                            ->where(['id' => $foreignId])
                            ->select(['name'])
                            ->findOne();

                        if ($foreignEntity) {
                            $entity->set($item->name . 'Name', $foreignEntity->get('name'));
                        }
                    }
                }

                yield $entity;
            }
        })();
    }

    /**
     * @return stdClass[]
     */
    public function getValueMapList(): array
    {
        $list = [];

        foreach ($this as $entity) {
            $list[] = $entity->getValueMap();
        }

        return $list;
    }
}
