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

use Espo\ORM\Entity;
use Espo\ORM\Repository\Option\SaveOptions;
use Espo\Core\Hook\Hook\BeforeSave;

/**
 * Hook: Aktualisiert lastSync + syncStatus (Advoware) und aiLastSync + aiSyncStatus (AI)
 * basierend auf dem neuesten Timestamp und schlechtesten Status der verknüpften Dokumente.
 */
class UpdateLastSyncFromDocuments implements BeforeSave
{
    public function __construct(
        private \Espo\ORM\EntityManager $entityManager
    ) {}

    public function beforeSave(Entity $entity, SaveOptions $options): void
    {
        if ($options->get('skipHooks')) {
            return;
        }

        if ($entity->isNew()) {
            return;
        }

        try {
            $pdo = $this->entityManager->getPDO();
            $aktenId = $entity->getId();

            // Single aggregation row — CASE inside MAX() avoids the mixed-aggregate bug.
            $stmt = $pdo->prepare(
                "SELECT
                     MAX(last_sync_timestamp) AS maxAdvLastSync,
                     MAX(ai_last_sync)        AS maxAiLastSync,
                     MAX(CASE
                         WHEN sync_status = 'failed'  THEN 2
                         WHEN sync_status IN ('new','unclean')
                              OR sync_status IS NULL OR sync_status = '' THEN 1
                         ELSE 0
                     END) AS advWorstLevel,
                     MAX(CASE
                         WHEN ai_sync_status = 'failed'  THEN 2
                         WHEN ai_sync_status IN ('new','unclean')
                              OR ai_sync_status IS NULL OR ai_sync_status = '' THEN 1
                         ELSE 0
                     END) AS aiWorstLevel,
                     -- ai_sync_status = unclean triggers graphParsingStatus
                     SUM(CASE WHEN ai_sync_status = 'unclean' THEN 1 ELSE 0 END) AS aiUncleanCount,
                     -- aiParsingStatus buckets
                     SUM(CASE WHEN ai_parsing_status = 'parsing'  THEN 1 ELSE 0 END) AS parseParsingCount,
                     SUM(CASE WHEN ai_parsing_status = 'complete' THEN 1 ELSE 0 END) AS parseCompleteCount,
                     SUM(CASE WHEN ai_parsing_status = 'failed'   THEN 1 ELSE 0 END) AS parseFailedCount,
                     COUNT(*) AS docCount
                 FROM c_dokumente
                 WHERE c_akten_id = :aktenId AND deleted = 0"
            );
            $stmt->execute([':aktenId' => $aktenId]);
            $row = $stmt->fetch(\PDO::FETCH_ASSOC);

            if (!$row || (int)$row['docCount'] === 0) {
                $entity->set('syncStatus', 'unclean');
                $entity->set('aiSyncStatus', 'unclean');
                $entity->set('aiParsingStatus', 'unknown');
                return;
            }

            $docCount = (int)$row['docCount'];

            // ── Timestamps ─────────────────────────────────────────────────
            if (!empty($row['maxAdvLastSync'])) {
                $entity->set('lastSync', $row['maxAdvLastSync']);
            }
            if (!empty($row['maxAiLastSync'])) {
                $entity->set('aiLastSync', $row['maxAiLastSync']);
            }

            // ── Advoware Sync Status (worst-case) ──────────────────────────
            $advLevel = (int)($row['advWorstLevel'] ?? 0);
            if ($advLevel >= 2) {
                $entity->set('syncStatus', 'failed');
            } elseif ($advLevel === 1) {
                $entity->set('syncStatus', 'unclean');
            } else {
                $entity->set('syncStatus', 'synced');
            }

            // ── AI Sync Status (worst-case) ────────────────────────────────
            $aiLevel = (int)($row['aiWorstLevel'] ?? 0);
            if ($aiLevel >= 2) {
                $entity->set('aiSyncStatus', 'failed');
            } elseif ($aiLevel === 1) {
                $entity->set('aiSyncStatus', 'unclean');
            } else {
                $entity->set('aiSyncStatus', 'synced');
            }

            // ── AI Parsing Status (aggregated across all documents) ─────────
            // Priority: parsing > unknown > complete_with_failures > complete
            $parseParsing  = (int)($row['parseParsingCount']  ?? 0);
            $parseComplete = (int)($row['parseCompleteCount'] ?? 0);
            $parseFailed   = (int)($row['parseFailedCount']   ?? 0);
            $parseUnknown  = $docCount - $parseParsing - $parseComplete - $parseFailed;

            if ($parseParsing > 0) {
                $entity->set('aiParsingStatus', 'parsing');
            } elseif ($parseUnknown > 0) {
                $entity->set('aiParsingStatus', 'unknown');
            } elseif ($parseFailed > 0) {
                // No unknown/parsing left, but some failures
                $entity->set('aiParsingStatus', 'complete_with_failures');
            } else {
                $entity->set('aiParsingStatus', 'complete');
            }

            // ── Graph Parsing Status (only auto-set to unclean, never reset) ─
            // If any document's AI sync status is currently unclean → graph is stale.
            // Any other transition (back to complete, etc.) must be done manually.
            if ((int)($row['aiUncleanCount'] ?? 0) > 0) {
                $entity->set('graphParsingStatus', 'unclean');
            }

        } catch (\Exception $e) {
            $GLOBALS['log']->error('CAkten UpdateLastSyncFromDocuments Hook Error: ' . $e->getMessage());
        }
    }
}
