<?php

namespace Espo\Custom\Api\JunctionData;

use Espo\Core\Api\Action;
use Espo\Core\Api\Request;
use Espo\Core\Api\Response;
use Espo\Core\Api\ResponseComposer;
use Espo\Core\Exceptions\BadRequest;
use Espo\Core\Exceptions\NotFound;
use Espo\Core\Exceptions\Conflict;
use Espo\ORM\EntityManager;

/**
 * POST /api/v1/JunctionData/CAIKnowledge/:knowledgeId/dokumentes/:documentId
 * 
 * Creates or updates relationship with junction table data
 * This endpoint links the entities AND sets junction columns in one call
 */
class LinkDokument implements Action
{
    public function __construct(
        private EntityManager $entityManager
    ) {}
    
    public function process(Request $request): Response
    {
        $knowledgeId = $request->getRouteParam('knowledgeId');
        $documentId = $request->getRouteParam('documentId');
        $data = $request->getParsedBody();
        
        if (!$knowledgeId || !$documentId) {
            throw new BadRequest('Knowledge ID and Document ID are required');
        }
        
        // Verify entities exist
        $knowledge = $this->entityManager->getEntityById('CAIKnowledge', $knowledgeId);
        if (!$knowledge) {
            throw new NotFound('Knowledge entry not found');
        }
        
        $document = $this->entityManager->getEntityById('CDokumente', $documentId);
        if (!$document) {
            throw new NotFound('Document not found');
        }
        
        $pdo = $this->entityManager->getPDO();
        
        // Check if link already exists
        $existing = $this->checkIfLinked($knowledgeId, $documentId);
        
        if ($existing) {
            // Link exists - update junction columns
            return $this->updateExisting($knowledgeId, $documentId, $data);
        }
        
        // Create new link via ORM (triggers hooks like DokumenteSyncStatus)
        $this->entityManager->getRDBRepository('CAIKnowledge')
            ->getRelation($knowledge, 'dokumentes')
            ->relate($document);
        
        // Now set junction columns if provided
        if (!empty((array)$data)) {
            return $this->updateExisting($knowledgeId, $documentId, $data);
        }
        
        // Return created entry
        $result = $this->getJunctionEntry($knowledgeId, $documentId);
        
        return ResponseComposer::json($result);
    }
    
    private function checkIfLinked(string $knowledgeId, string $documentId): bool
    {
        $pdo = $this->entityManager->getPDO();
        
        $sql = "
            SELECT COUNT(*) as count
            FROM c_a_i_knowledge_dokumente
            WHERE c_a_i_knowledge_id = :knowledgeId
              AND c_dokumente_id = :documentId
              AND deleted = 0
        ";
        
        $sth = $pdo->prepare($sql);
        $sth->execute([
            'knowledgeId' => $knowledgeId,
            'documentId' => $documentId
        ]);
        
        $result = $sth->fetch(\PDO::FETCH_ASSOC);
        return $result['count'] > 0;
    }
    
    private function updateExisting(string $knowledgeId, string $documentId, \stdClass $data): Response
    {
        $pdo = $this->entityManager->getPDO();
        
        // Build dynamic UPDATE SET clause
        $setClauses = [];
        $params = [
            'knowledgeId' => $knowledgeId,
            'documentId' => $documentId
        ];
        
        if (isset($data->aiDocumentId)) {
            $setClauses[] = "ai_document_id = :aiDocumentId";
            $params['aiDocumentId'] = $data->aiDocumentId;
        }
        
        if (isset($data->syncstatus)) {
            $allowedStatuses = ['new', 'unclean', 'synced', 'failed', 'unsupported'];
            if (!in_array($data->syncstatus, $allowedStatuses)) {
                throw new BadRequest('Invalid syncstatus value. Allowed: ' . implode(', ', $allowedStatuses));
            }
            $setClauses[] = "syncstatus = :syncstatus";
            $params['syncstatus'] = $data->syncstatus;
        }
        
        if (isset($data->lastSync)) {
            $setClauses[] = "last_sync = :lastSync";
            $params['lastSync'] = $data->lastSync;
        } elseif (isset($data->updateLastSync) && $data->updateLastSync === true) {
            $setClauses[] = "last_sync = NOW()";
        }
        
        if (!empty($setClauses)) {
            $sql = "
                UPDATE c_a_i_knowledge_dokumente
                SET " . implode(', ', $setClauses) . "
                WHERE c_a_i_knowledge_id = :knowledgeId
                  AND c_dokumente_id = :documentId
                  AND deleted = 0
            ";
            
            $sth = $pdo->prepare($sql);
            $sth->execute($params);
        }
        
        // Return updated data
        $result = $this->getJunctionEntry($knowledgeId, $documentId);
        
        return ResponseComposer::json($result);
    }
    
    private function getJunctionEntry(string $knowledgeId, string $documentId): array
    {
        $pdo = $this->entityManager->getPDO();
        
        $sql = "
            SELECT 
                id as junctionId,
                c_a_i_knowledge_id as cAIKnowledgeId,
                c_dokumente_id as cDokumenteId,
                ai_document_id as aiDocumentId,
                syncstatus,
                last_sync as lastSync
            FROM c_a_i_knowledge_dokumente
            WHERE c_a_i_knowledge_id = :knowledgeId
              AND c_dokumente_id = :documentId
              AND deleted = 0
        ";
        
        $sth = $pdo->prepare($sql);
        $sth->execute([
            'knowledgeId' => $knowledgeId,
            'documentId' => $documentId
        ]);
        
        $result = $sth->fetch(\PDO::FETCH_ASSOC);
        
        if (!$result) {
            throw new NotFound('Junction entry not found');
        }
        
        return $result;
    }
}
