<?php

namespace Espo\Modules\SmartAssistant\Services;

use Espo\Core\Exceptions\Error;
use Espo\Core\Exceptions\NotFound;
use Espo\Core\InjectableFactory;
use Espo\Core\Utils\Log;
use Espo\ORM\EntityManager;
use Espo\Entities\User;
use Espo\Modules\NetworkStorageIntegration\Services\DocumentTemplateService;
use Espo\Modules\NetworkStorageIntegration\Services\NetworkDocumentService;
use PhpOffice\PhpWord\TemplateProcessor;

class GenericTemplateGenerator
{
    private const TEMP_DIR = 'data/tmp/';

    public function __construct(
        private EntityManager $entityManager,
        private InjectableFactory $injectableFactory,
        private Log $log,
        private User $user
    ) {}

    public function generate(string $templateId, string $caseId, ?string $documentSubject = null, array $customPlaceholders = []): array
    {
        $template = $this->entityManager->getEntityById('DocumentTemplate', $templateId);
        if (!$template) {
            throw new NotFound("Template {$templateId} not found.");
        }

        if (!$template->get('isActive')) {
            throw new Error("Template is not active.");
        }

        $templatePath = $template->get('templatePath');
        if (!$templatePath) {
            throw new Error("Template path is not configured.");
        }

        $case = $this->entityManager->getEntityById('Case', $caseId);
        if (!$case) {
            throw new NotFound("Case {$caseId} not found.");
        }

        $templateName = $template->get('name') ?? 'document';

        // Step 1: Download template from WebDAV
        $localTemplatePath = $this->downloadTemplate($templatePath);

        try {
            // Step 2: Build placeholder data from entity fields
            $templateService = $this->injectableFactory->create(DocumentTemplateService::class);
            $placeholderData = $templateService->buildPlaceholderData($case);

            // Step 3: Merge custom placeholders (override entity data)
            foreach ($customPlaceholders as $key => $value) {
                $placeholderData[$key] = $value;
            }

            // Step 4: Process template
            $outputPath = self::TEMP_DIR . uniqid('gen_') . '.docx';
            if (!is_dir(self::TEMP_DIR)) {
                mkdir(self::TEMP_DIR, 0775, true);
            }

            $this->processTemplate($localTemplatePath, $outputPath, $placeholderData);

            // Step 5: Read generated content
            $content = file_get_contents($outputPath);
            @unlink($outputPath);
            @unlink($localTemplatePath);

            // Step 6: Build document name
            $contactName = $this->getContactName($case);
            $docName = $documentSubject ?? "{$templateName} — {$contactName}";

            // Step 7: Create Attachment + Document
            $attachment = $this->entityManager->getNewEntity('Attachment');
            $attachment->set([
                'name' => $docName . '.docx',
                'type' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
                'role' => 'Attachment',
                'size' => strlen($content),
                'relatedType' => 'Document',
            ]);
            $this->entityManager->saveEntity($attachment);
            file_put_contents('data/upload/' . $attachment->getId(), $content);

            $document = $this->entityManager->getNewEntity('Document');
            $document->set([
                'name' => $docName,
                'fileId' => $attachment->getId(),
                'fileName' => $docName . '.docx',
                'assignedUserId' => $this->user->getId(),
            ]);
            $this->entityManager->saveEntity($document);

            // Link to Case
            $this->entityManager->getRDBRepository('Case')
                ->getRelation($case, 'documents')
                ->relate($document);

            $this->log->info("GenericTemplateGenerator: Created '{$docName}' from template '{$templateName}' for Case {$caseId}");

            return [
                'success' => true,
                'message' => "✅ מסמך \"{$docName}\" נוצר בהצלחה מתבנית \"{$templateName}\"\n📄 המסמך צורף לתיק.",
                'entityType' => 'Document',
                'entityId' => $document->getId(),
            ];
        } catch (\Exception $e) {
            if (isset($localTemplatePath) && file_exists($localTemplatePath)) {
                @unlink($localTemplatePath);
            }
            throw $e;
        }
    }

    private function downloadTemplate(string $templatePath): string
    {
        // Try local paths first
        if (file_exists($templatePath)) {
            return $templatePath;
        }

        $localPath = 'data/document-templates/' . ltrim($templatePath, '/');
        if (file_exists($localPath)) {
            return $localPath;
        }

        // Download from NetworkStorage (WebDAV)
        try {
            $nds = $this->injectableFactory->create(NetworkDocumentService::class);
            $client = $nds->getClient();

            $integration = $this->entityManager->getEntityById('Integration', 'NetworkStorage');
            $templatesFolderPath = 'Templates';
            if ($integration && $integration->get('enabled')) {
                $data = (array) ($integration->get('data') ?? []);
                $templatesFolderPath = $data['templatesFolderPath'] ?? 'Templates';
            }

            $storagePath = $templatesFolderPath . '/' . $templatePath;

            if (!$client->exists($storagePath)) {
                throw new Error("Template file not found on storage: {$storagePath}");
            }

            $content = $client->downloadFile($storagePath);

            if (!is_dir(self::TEMP_DIR)) {
                mkdir(self::TEMP_DIR, 0775, true);
            }
            $tmpPath = self::TEMP_DIR . 'tpl_' . uniqid() . '.docx';
            file_put_contents($tmpPath, $content);

            return $tmpPath;
        } catch (Error $e) {
            throw $e;
        } catch (\Exception $e) {
            throw new Error("Failed to download template: " . $e->getMessage());
        }
    }

    private function processTemplate(string $inputPath, string $outputPath, array $data): void
    {
        if (!class_exists(TemplateProcessor::class, false)) {
            $autoloader = 'vendor/phpoffice/phpword/src/PhpWord/Autoloader.php';
            if (file_exists($autoloader)) {
                require_once $autoloader;
                \PhpOffice\PhpWord\Autoloader::register();
            }
        }

        $processor = new TemplateProcessor($inputPath);

        foreach ($data as $key => $value) {
            if ($value === null) {
                $value = '';
            }
            if (is_array($value)) {
                $value = implode(', ', $value);
            } elseif (is_bool($value)) {
                $value = $value ? 'כן' : 'לא';
            }
            $processor->setValue($key, (string) $value);
        }

        $processor->saveAs($outputPath);
    }

    private function getContactName($case): string
    {
        $contactId = $case->get('contactId');
        if (!$contactId) {
            $ids = $case->getLinkMultipleIdList('contacts');
            if (!empty($ids)) {
                $contactId = $ids[0];
            }
        }

        if ($contactId) {
            $contact = $this->entityManager->getEntityById('Contact', $contactId);
            if ($contact) {
                return trim($contact->get('firstName') . ' ' . $contact->get('lastName'));
            }
        }

        return $case->get('name') ?? '';
    }
}
