<?php

declare(strict_types=1);

namespace App\Domain\Meta\Http\Controller;

use App\Domain\Meta\Entity\MetaEntry;
use App\Domain\Meta\Http\Request\MetaRequest;
use App\Domain\Meta\Repository\MetaRepositoryInterface;
use App\Domain\Meta\Service\MetaManager;
use App\Domain\Meta\Service\MetaTemplateResolver;
use App\Domain\Meta\ValueObject\MetaData;
use App\Framework\Http\JsonResult;
use App\Framework\Http\Status;
use App\Framework\Router\Attributes\Route;
use App\Framework\Router\Method;

final class MetaAdminController
{
    public function __construct(
        private readonly MetaRepositoryInterface $repository,
        private readonly MetaManager $metaManager,
        private readonly ?MetaTemplateResolver $templateResolver = null,
    ) {}

    /**
     * Listet alle Meta-Einträge auf
     */
    #[Route(path: '/admin/meta', method: Method::GET)]
    public function listMeta(): JsonResult
    {
        try {
            $page = (int) ($_GET['page'] ?? 1);
            $limit = (int) ($_GET['limit'] ?? 50);
            $search = $_GET['search'] ?? '';

            $offset = ($page - 1) * $limit;

            if ($search) {
                $entries = $this->repository->search($search, $limit);
                $total = count($entries);
            } else {
                $entries = $this->repository->findAll($limit, $offset);
                $total = $this->repository->count();
            }

            return new JsonResult([
                'success' => true,
                'data' => array_map(fn($entry) => $entry->toArray(), $entries),
                'pagination' => [
                    'page' => $page,
                    'limit' => $limit,
                    'total' => $total,
                    'pages' => ceil($total / $limit),
                ]
            ]);
        } catch (\Exception $e) {
            return new JsonResult([
                'success' => false,
                'error' => $e->getMessage()
            ], Status::INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * Zeigt einen einzelnen Meta-Eintrag
     */
    #[Route(path: '/admin/meta/{id}', method: Method::GET)]
    public function getMeta(int $id): JsonResult
    {
        try {
            $entry = $this->repository->findById($id);

            if (!$entry) {
                return new JsonResult([
                    'success' => false,
                    'error' => 'Meta-Eintrag nicht gefunden'
                ], Status::NOT_FOUND);
            }

            return new JsonResult([
                'success' => true,
                'data' => $entry->toArray()
            ]);
        } catch (\Exception $e) {
            return new JsonResult([
                'success' => false,
                'error' => $e->getMessage()
            ], Status::INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * Erstellt einen neuen Meta-Eintrag
     */
    #[Route(path: '/admin/meta', method: Method::POST)]
    public function createMeta(MetaRequest $request): JsonResult
    {
        try {
            // Validierung: Entweder Route oder Entity muss angegeben sein
            if (!$request->routePattern && (!$request->entityType || !$request->entityId)) {
                return new JsonResult([
                    'success' => false,
                    'error' => 'Entweder Route-Pattern oder Entity-Typ/ID muss angegeben werden'
                ], Status::BAD_REQUEST);
            }

            // Prüfe auf Duplikate
            if ($request->routePattern && $this->repository->routePatternExists($request->routePattern)) {
                return new JsonResult([
                    'success' => false,
                    'error' => 'Route-Pattern existiert bereits'
                ], Status::CONFLICT);
            }

            if ($request->entityType && $request->entityId &&
                $this->repository->entityMetaExists($request->entityType, $request->entityId)) {
                return new JsonResult([
                    'success' => false,
                    'error' => 'Meta-Daten für diese Entity existieren bereits'
                ], Status::CONFLICT);
            }

            // Template validieren
            if ($this->templateResolver) {
                $this->validateTemplates($request);
            }

            $metaData = new MetaData(
                title: $request->title,
                description: $request->description,
                keywords: $request->getKeywordsAsArray(),
                ogTitle: $request->ogTitle,
                ogDescription: $request->ogDescription,
                ogImage: $request->ogImage,
                ogType: $request->ogType,
                twitterCard: $request->twitterCard,
                twitterSite: $request->twitterSite,
                canonical: $request->canonical,
                customMeta: $request->customMeta
            );

            $entry = new MetaEntry(
                routePattern: $request->routePattern,
                entityType: $request->entityType,
                entityId: $request->entityId,
                metaData: $metaData,
                priority: $request->priority,
                active: $request->active
            );

            $savedEntry = $this->repository->save($entry);

            // Cache invalidieren
            if ($request->routePattern) {
                $this->metaManager->invalidateCache($request->routePattern);
            }

            return new JsonResult([
                'success' => true,
                'data' => $savedEntry->toArray()
            ], Status::CREATED);
        } catch (\Exception $e) {
            return new JsonResult([
                'success' => false,
                'error' => $e->getMessage()
            ], Status::INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * Aktualisiert einen Meta-Eintrag
     */
    #[Route(path: '/admin/meta/{id}', method: Method::PUT)]
    public function updateMeta(int $id, MetaRequest $request): JsonResult
    {
        try {
            $entry = $this->repository->findById($id);

            if (!$entry) {
                return new JsonResult([
                    'success' => false,
                    'error' => 'Meta-Eintrag nicht gefunden'
                ], Status::NOT_FOUND);
            }

            // Prüfe auf Duplikate (außer dem aktuellen Eintrag)
            if ($request->routePattern &&
                $this->repository->routePatternExists($request->routePattern, $id)) {
                return new JsonResult([
                    'success' => false,
                    'error' => 'Route-Pattern existiert bereits'
                ], Status::CONFLICT);
            }

            if ($request->entityType && $request->entityId &&
                $this->repository->entityMetaExists($request->entityType, $request->entityId, $id)) {
                return new JsonResult([
                    'success' => false,
                    'error' => 'Meta-Daten für diese Entity existieren bereits'
                ], Status::CONFLICT);
            }

            // Template validieren
            if ($this->templateResolver) {
                $this->validateTemplates($request);
            }

            $metaData = new MetaData(
                title: $request->title,
                description: $request->description,
                keywords: $request->getKeywordsAsArray(),
                ogTitle: $request->ogTitle,
                ogDescription: $request->ogDescription,
                ogImage: $request->ogImage,
                ogType: $request->ogType,
                twitterCard: $request->twitterCard,
                twitterSite: $request->twitterSite,
                canonical: $request->canonical,
                customMeta: $request->customMeta
            );

            $entry->routePattern = $request->routePattern;
            $entry->entityType = $request->entityType;
            $entry->entityId = $request->entityId;
            $entry->priority = $request->priority;
            $entry->active = $request->active;
            $entry->updateMetaData($metaData);

            $savedEntry = $this->repository->save($entry);

            // Cache invalidieren
            $this->metaManager->invalidateAllCache();

            return new JsonResult([
                'success' => true,
                'data' => $savedEntry->toArray()
            ]);
        } catch (\Exception $e) {
            return new JsonResult([
                'success' => false,
                'error' => $e->getMessage()
            ], Status::INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * Löscht einen Meta-Eintrag
     */
    #[Route(path: '/admin/meta/{id}', method: Method::DELETE)]
    public function deleteMeta(int $id): JsonResult
    {
        try {
            $entry = $this->repository->findById($id);

            if (!$entry) {
                return new JsonResult([
                    'success' => false,
                    'error' => 'Meta-Eintrag nicht gefunden'
                ], Status::NOT_FOUND);
            }

            $deleted = $this->repository->delete($id);

            if ($deleted) {
                // Cache invalidieren
                $this->metaManager->invalidateAllCache();

                return new JsonResult([
                    'success' => true,
                    'message' => 'Meta-Eintrag erfolgreich gelöscht'
                ]);
            } else {
                return new JsonResult([
                    'success' => false,
                    'error' => 'Meta-Eintrag konnte nicht gelöscht werden'
                ], Status::INTERNAL_SERVER_ERROR);
            }
        } catch (\Exception $e) {
            return new JsonResult([
                'success' => false,
                'error' => $e->getMessage()
            ], Status::INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * Aktiviert/Deaktiviert einen Meta-Eintrag
     */
    #[Route(path: '/admin/meta/{id}/toggle', method: Method::POST)]
    public function toggleMeta(int $id): JsonResult
    {
        try {
            $entry = $this->repository->findById($id);

            if (!$entry) {
                return new JsonResult([
                    'success' => false,
                    'error' => 'Meta-Eintrag nicht gefunden'
                ], Status::NOT_FOUND);
            }

            if ($entry->active) {
                $entry->deactivate();
            } else {
                $entry->activate();
            }

            $savedEntry = $this->repository->save($entry);

            // Cache invalidieren
            $this->metaManager->invalidateAllCache();

            return new JsonResult([
                'success' => true,
                'data' => $savedEntry->toArray()
            ]);
        } catch (\Exception $e) {
            return new JsonResult([
                'success' => false,
                'error' => $e->getMessage()
            ], Status::INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * Validiert Template-Syntax
     */
    #[Route(path: '/admin/meta/validate-template', method: Method::POST)]
    public function validateTemplate(): JsonResult
    {
        try {
            $template = $_POST['template'] ?? '';

            if (!$this->templateResolver) {
                return new JsonResult([
                    'success' => true,
                    'message' => 'Template-Validation nicht verfügbar'
                ]);
            }

            $errors = $this->templateResolver->validateTemplate($template);
            $placeholders = $this->templateResolver->extractPlaceholders($template);

            return new JsonResult([
                'success' => true,
                'data' => [
                    'valid' => empty($errors),
                    'errors' => $errors,
                    'placeholders' => $placeholders
                ]
            ]);
        } catch (\Exception $e) {
            return new JsonResult([
                'success' => false,
                'error' => $e->getMessage()
            ], Status::INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * Cache für Meta-Daten leeren
     */
    #[Route(path: '/admin/meta/clear-cache', method: Method::POST)]
    public function clearCache(): JsonResult
    {
        try {
            $this->metaManager->invalidateAllCache();

            return new JsonResult([
                'success' => true,
                'message' => 'Meta-Cache erfolgreich geleert'
            ]);
        } catch (\Exception $e) {
            return new JsonResult([
                'success' => false,
                'error' => $e->getMessage()
            ], Status::INTERNAL_SERVER_ERROR);
        }
    }

    private function validateTemplates(MetaRequest $request): void
    {
        if (!$this->templateResolver) {
            return;
        }

        $templates = [
            'title' => $request->title,
            'description' => $request->description,
            'ogTitle' => $request->ogTitle,
            'ogDescription' => $request->ogDescription,
            'canonical' => $request->canonical,
        ];

        foreach ($templates as $field => $template) {
            if ($template) {
                $errors = $this->templateResolver->validateTemplate($template);
                if (!empty($errors)) {
                    throw new \InvalidArgumentException("Template-Fehler in {$field}: " . implode(', ', $errors));
                }
            }
        }
    }
}
