<?php

namespace App\Services\PageBuilder;

use App\Models\Page;
use App\Models\PageRevision;
use App\PageBuilder\ComponentRegistry;
use App\Services\TranslationService;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

/**
 * Sayfa içeriğini (page-builder bloklar + meta) hedef locale'e çevirir.
 *
 * - Component schema'larını kullanarak text/textarea alanlarını tespit eder.
 * - URL/icon/sınıf gibi text türünden ama çevrilmesi yanlış olacak alanları
 *   isim pattern'i ile dışarda bırakır.
 * - DeepL üzerinden batch çeviri yapar, content'i blok-bazlı geri yazar.
 * - Hedef sayfa yoksa aynı translation_group altında oluşturur, varsa draft revision atıp
 *   üstüne yazar (overwrite=true).
 */
class PageContentTranslator
{
    /** Adı bu pattern'lerden birine uyan text alanları çevrilmez (FA icon, URL, CSS class, vb.). */
    private const NON_TRANSLATABLE_PATTERNS = [
        '/^icon$/i',
        '/icon_class$/i',
        '/^fa_/i',
        '/_url$/i',
        '/^url$/i',
        '/^link$/i',
        '/_link$/i',
        '/^slug$/i',
        '/^anchor$/i',
        '/^css_class$/i',
        '/^image$/i',
        '/_image$/i',
        '/^src$/i',
        '/^embed$/i',
        '/^code$/i',
        '/^target$/i',
    ];

    public function __construct(
        private readonly ComponentRegistry $registry,
        private readonly TranslationService $translator,
    ) {}

    /**
     * Source page'i targetLocale'e çevir, mevcut translation_group içindeki hedef sayfaya yaz.
     * Hedef sayfa yoksa oluşturur.
     *
     * @return Page Hedef sayfa (taze).
     */
    public function translatePage(Page $source, string $targetLocale, ?int $adminId = null): Page
    {
        $target = Page::where('translation_group_id', $source->translation_group_id)
            ->where('locale', $targetLocale)
            ->first();

        return DB::transaction(function () use ($source, $target, $targetLocale, $adminId) {
            // Hedef yoksa oluştur (placeholder slug, admin sonradan değiştirir)
            if (! $target) {
                $target = Page::create([
                    'brand_id' => $source->brand_id,
                    'translation_group_id' => $source->translation_group_id,
                    'locale' => $targetLocale,
                    'slug' => $source->slug.'-'.$targetLocale,
                    'title' => $source->title,
                    'content' => ['blocks' => []],
                    'status' => 'draft',
                    'is_home' => false,
                    'created_by_admin_id' => $adminId,
                ]);
            } else {
                // Mevcut state'i revision olarak sakla (rollback için)
                PageRevision::create([
                    'page_id' => $target->id,
                    'content' => $target->content,
                    'title' => $target->title,
                    'slug' => $target->slug,
                    'meta_title' => $target->meta_title,
                    'meta_description' => $target->meta_description,
                    'meta_keywords' => $target->meta_keywords,
                    'og_image' => $target->og_image,
                    'canonical_url' => $target->canonical_url,
                    'robots' => $target->robots,
                    'schema_json' => $target->schema_json,
                    'status' => $target->status,
                    'created_by_admin_id' => $adminId,
                    'created_at' => now(),
                ]);
            }

            // Toplanacak metinler: meta + content
            $strings = $this->collectStrings($source);

            // Boş array ise translate API'sini çağırma
            if (empty($strings)) {
                $target->save();
                return $target->fresh();
            }

            // DeepL'e batch gönder
            $sourceLocale = $source->locale;
            $translated = $this->translator->translateBatch(
                array_column($strings, 'text'),
                $targetLocale,
                $sourceLocale,
            );

            // Strings + translated'ı birleştir, hedef alanlara yaz
            $newContent = $source->content ?? ['blocks' => []];
            $metaUpdates = [];

            foreach ($strings as $idx => $entry) {
                $value = $translated[$idx] ?? $entry['text'];
                if ($entry['kind'] === 'meta') {
                    $metaUpdates[$entry['field']] = $value;
                } elseif ($entry['kind'] === 'block') {
                    $this->setByPath($newContent['blocks'][$entry['block_idx']]['data'], $entry['path'], $value);
                }
            }

            $target->fill([
                'title' => $metaUpdates['title'] ?? $target->title,
                'meta_title' => $metaUpdates['meta_title'] ?? $target->meta_title,
                'meta_description' => $metaUpdates['meta_description'] ?? $target->meta_description,
                'meta_keywords' => $metaUpdates['meta_keywords'] ?? $target->meta_keywords,
                'content' => $newContent,
            ]);
            if ($adminId) $target->updated_by_admin_id = $adminId;
            $target->save();

            return $target->fresh();
        });
    }

    /**
     * @return array<int, array{kind: string, field?: string, block_idx?: int, path?: array, text: string}>
     */
    public function collectStrings(Page $page): array
    {
        $out = [];

        foreach (['title', 'meta_title', 'meta_description', 'meta_keywords'] as $f) {
            $val = $page->{$f};
            if (is_string($val) && trim($val) !== '') {
                $out[] = ['kind' => 'meta', 'field' => $f, 'text' => $val];
            }
        }

        $blocks = $page->content['blocks'] ?? [];
        foreach ($blocks as $i => $block) {
            $type = $block['type'] ?? null;
            $data = $block['data'] ?? [];
            if (! $type) continue;

            $component = $this->registry->resolve($type);
            if (! $component) continue;

            $schema = $component->schema();
            $this->walkSchema($schema, $data, [], function (array $path, string $text) use (&$out, $i) {
                $out[] = [
                    'kind' => 'block',
                    'block_idx' => $i,
                    'path' => $path,
                    'text' => $text,
                ];
            });
        }

        return $out;
    }

    private function walkSchema(array $schema, array $data, array $path, callable $emit): void
    {
        foreach ($schema as $key => $def) {
            // 'options' ana key — wrapper'a ait, çevrilmez
            if ($key === 'options') continue;
            if (! is_array($def)) continue;

            $type = $def['type'] ?? null;
            $value = $data[$key] ?? null;
            $newPath = [...$path, $key];

            if ($type === 'repeater') {
                if (! is_array($value)) continue;
                // Component schema'ları repeater item alanı için 'item_schema' anahtarı
                // kullanıyor (eski 'fields' değil). Yanlış anahtarda items skip oluyordu.
                $itemSchema = $def['item_schema'] ?? $def['fields'] ?? [];
                if (! is_array($itemSchema)) continue;
                foreach ($value as $idx => $item) {
                    if (! is_array($item)) continue;
                    $this->walkSchema($itemSchema, $item, [...$newPath, $idx], $emit);
                }
                continue;
            }

            if (in_array($type, ['text', 'textarea', 'richtext', 'wysiwyg'], true)) {
                if (($def['translatable'] ?? null) === false) continue;
                if ($this->isFieldNonTranslatable($key)) continue;
                if (is_string($value) && trim($value) !== '') {
                    $emit($newPath, $value);
                }
            }
        }
    }

    private function isFieldNonTranslatable(string $name): bool
    {
        foreach (self::NON_TRANSLATABLE_PATTERNS as $pattern) {
            if (preg_match($pattern, $name)) return true;
        }
        return false;
    }

    private function setByPath(array &$container, array $path, mixed $value): void
    {
        $ref = &$container;
        $last = count($path) - 1;
        foreach ($path as $i => $segment) {
            if ($i === $last) {
                $ref[$segment] = $value;
                return;
            }
            if (! isset($ref[$segment]) || ! is_array($ref[$segment])) {
                $ref[$segment] = [];
            }
            $ref = &$ref[$segment];
        }
    }
}
