<?php
namespace Espo\Custom\Hooks\CDokumente;

use Espo\ORM\Entity;
use Espo\Core\Hook\Hook\AfterRelate;
use Espo\Core\Hook\Hook\AfterUnrelate;
use Espo\ORM\Repository\Option\RelateOptions;
use Espo\ORM\Repository\Option\UnrelateOptions;

/**
 * Hook: Sync-Status-Aktualisierung wenn ein Dokument über die CDokumente-Panels
 * mit einer Räumungsklage oder einem Mietinkasso verknüpft oder entknüpft wird.
 *
 * Auslöser (von CDokumente-Seite aus):
 * - afterRelate   'vmhRumungsklagesdokumente'  → Räumungsklage verknüpft
 * - afterRelate   'mietinkassosdokumente'       → Mietinkasso verknüpft
 * - afterUnrelate 'vmhRumungsklagesdokumente'  → Räumungsklage entknüpft
 * - afterUnrelate 'mietinkassosdokumente'       → Mietinkasso entknüpft
 *
 * Wenn die Verknüpfung von der Räumungsklage/Mietinkasso-Seite kommt, feuern
 * stattdessen CVmhRumungsklage/CMietinkasso::PropagateDocuments — dieses Hook
 * feuert dann NICHT (EspoCRM feuert afterRelate nur auf der aufrufenden Seite).
 */
class SyncStatusOnRelate implements AfterRelate, AfterUnrelate
{
    /** Relation → [parentEntityType, advowareAktenRelation, aiKnowledgeRelation] */
    private const RELATION_MAP = [
        'vmhRumungsklagesdokumente' => ['CVmhRumungsklage', 'advowareAkten', 'aIKnowledge'],
        'mietinkassosdokumente'     => ['CMietinkasso',      'advowareAkten', 'aIKnowledge'],
    ];

    /** @var array<string, bool> */
    private static array $processing = [];

    public function __construct(
        private \Espo\ORM\EntityManager $entityManager
    ) {}

    // -------------------------------------------------------------------------

    public function afterRelate(
        Entity $entity,
        string $relationName,
        Entity $foreignEntity,
        array $columnData,
        RelateOptions $options
    ): void {
        if (!isset(self::RELATION_MAP[$relationName])) {
            return;
        }

        $key = $entity->getId() . '-' . $foreignEntity->getId() . '-' . $relationName . '-relate';
        if (isset(self::$processing[$key])) {
            return;
        }
        self::$processing[$key] = true;

        try {
            [, $aktenRelation, $aiKnowledgeRelation] = self::RELATION_MAP[$relationName];

            // AdvowareAkten über die Parent-Entity ermitteln
            $advowareAkten = $this->entityManager
                ->getRDBRepository($foreignEntity->getEntityType())
                ->getRelation($foreignEntity, $aktenRelation)
                ->findOne();

            if ($advowareAkten) {
                $entity->set('cAktenId', $advowareAkten->getId());
                $entity->set('syncStatus', 'unclean');
                $entity->set('aiSyncStatus', 'unclean');
                $entity->set('aiParsingStatus', 'unknown');
                $this->entityManager->saveEntity($entity, ['silent' => true, 'skipHooks' => true]);

                $this->triggerAkteUpdate($advowareAkten->getId());
            } else {
                // Kein Akte-Link — trotzdem Sync-Status auf unclean setzen
                $entity->set('syncStatus', 'unclean');
                $entity->set('aiSyncStatus', 'unclean');
                $entity->set('aiParsingStatus', 'unknown');
                $this->entityManager->saveEntity($entity, ['silent' => true, 'skipHooks' => true]);
            }

            // AIKnowledge-Verknüpfung propagieren
            $aiKnowledge = $this->entityManager
                ->getRDBRepository($foreignEntity->getEntityType())
                ->getRelation($foreignEntity, $aiKnowledgeRelation)
                ->findOne();

            if ($aiKnowledge) {
                $this->relateIfNotAlready($aiKnowledge, 'dokumentes', $entity);
            }

        } catch (\Exception $e) {
            $GLOBALS['log']->error(
                'CDokumente SyncStatusOnRelate afterRelate (' . $relationName . ') Error: ' . $e->getMessage()
            );
        } finally {
            unset(self::$processing[$key]);
        }
    }

    // -------------------------------------------------------------------------

    public function afterUnrelate(
        Entity $entity,
        string $relationName,
        Entity $foreignEntity,
        UnrelateOptions $options
    ): void {
        if (!isset(self::RELATION_MAP[$relationName])) {
            return;
        }

        $key = $entity->getId() . '-' . $foreignEntity->getId() . '-' . $relationName . '-unrelate';
        if (isset(self::$processing[$key])) {
            return;
        }
        self::$processing[$key] = true;

        try {
            [, $aktenRelation, $aiKnowledgeRelation] = self::RELATION_MAP[$relationName];

            // Alte Akte ermitteln
            $advowareAkten = $this->entityManager
                ->getRDBRepository($foreignEntity->getEntityType())
                ->getRelation($foreignEntity, $aktenRelation)
                ->findOne();

            $oldAkteId = null;

            if ($advowareAkten && $entity->get('cAktenId') === $advowareAkten->getId()) {
                $oldAkteId = $advowareAkten->getId();
                $entity->set('cAktenId', null);
                $entity->set('syncStatus', 'unclean');
                $entity->set('aiSyncStatus', 'unclean');
                $this->entityManager->saveEntity($entity, ['silent' => true, 'skipHooks' => true]);
            }

            if ($oldAkteId) {
                $this->triggerAkteUpdate($oldAkteId);
            }

            // AIKnowledge-Verknüpfung entfernen
            $aiKnowledge = $this->entityManager
                ->getRDBRepository($foreignEntity->getEntityType())
                ->getRelation($foreignEntity, $aiKnowledgeRelation)
                ->findOne();

            if ($aiKnowledge) {
                $this->unrelateIfExists($aiKnowledge, 'dokumentes', $entity);
            }

        } catch (\Exception $e) {
            $GLOBALS['log']->error(
                'CDokumente SyncStatusOnRelate afterUnrelate (' . $relationName . ') Error: ' . $e->getMessage()
            );
        } finally {
            unset(self::$processing[$key]);
        }
    }

    // -------------------------------------------------------------------------

    private function triggerAkteUpdate(string $akteId): void
    {
        $akte = $this->entityManager->getEntityById('CAkten', $akteId);
        if ($akte) {
            $this->entityManager->saveEntity($akte, ['silent' => true]);
        }
    }

    private function relateIfNotAlready(Entity $parentEntity, string $relationName, Entity $document): void
    {
        $repository = $this->entityManager->getRDBRepository($parentEntity->getEntityType());
        $relation = $repository->getRelation($parentEntity, $relationName);

        $isRelated = $relation->where(['id' => $document->getId()])->findOne();
        if (!$isRelated) {
            $relation->relate($document);
        }
    }

    private function unrelateIfExists(Entity $parentEntity, string $relationName, Entity $document): void
    {
        $repository = $this->entityManager->getRDBRepository($parentEntity->getEntityType());
        $relation = $repository->getRelation($parentEntity, $relationName);

        $isRelated = $relation->where(['id' => $document->getId()])->findOne();
        if ($isRelated) {
            $relation->unrelate($document);
        }
    }
}
