<?php

namespace App\Services\Search;

use App\Models\Language;
use App\Models\Post;
use Illuminate\Support\Collection;
use Meilisearch\Client;

abstract class PostSearchIndexer
{
    public function __construct(protected readonly Client $client)
    {
    }

    abstract protected function indexName(): string;

    abstract protected function postType(): string;

    public function ensureIndexConfigured(): void
    {
        $index = $this->client->index($this->indexName());

        // primaryKey set — index yoksa oluştur, varsa primaryKey'i güncelle.
        // Doc'larda 'id' ve 'post_id' birlikte var; otomatik inference fail
        // olur, bu yüzden manuel set şart.
        try {
            $existingKey = $index->fetchPrimaryKey();
        } catch (\Throwable) {
            $existingKey = null;
        }

        if ($existingKey === null) {
            try {
                $task = $this->client->createIndex($this->indexName(), ['primaryKey' => 'id']);
                $this->client->waitForTask($task['taskUid']);
            } catch (\Throwable) {
                // Index'in oluşması bir başka koşulda gerçekleşebilir; sessizce devam et.
            }

            try {
                if ($index->fetchPrimaryKey() === null) {
                    $task = $index->update(['primaryKey' => 'id']);
                    $this->client->waitForTask($task['taskUid']);
                }
            } catch (\Throwable) {
            }
        }

        // Searchable + filterable attributes
        $index->updateSearchableAttributes(['title', 'content', 'excerpt', 'tags', 'subtype']);
        $index->updateFilterableAttributes(['post_id', 'language', 'status', 'is_featured', 'tags', 'subtype']);
    }

    /**
     * Bu post için tüm doc'ları sil ve published ise per-locale yenilerini yaz.
     */
    public function reindex(Post $post): void
    {
        if ($post->type !== $this->postType()) {
            return;
        }

        $index = $this->client->index($this->indexName());

        try {
            $index->deleteDocuments(['filter' => "post_id = {$post->id}"]);
        } catch (\Throwable) {
            foreach (Language::where('status', true)->pluck('a2_iso') as $loc) {
                try {
                    $index->deleteDocument("{$post->id}_{$loc}");
                } catch (\Throwable) {
                }
            }
        }

        if (! $post->isPublished()) {
            return;
        }

        $tagSlugs = $post->tags->pluck('slug')->all();

        $docs = [];
        foreach (Language::where('status', true)->pluck('a2_iso') as $locale) {
            $title = $post->getTranslation('title', $locale);
            $content = $post->getTranslation('content', $locale);
            $excerpt = $post->getTranslation('excerpt', $locale);
            if (empty($title) && empty($content)) {
                continue;
            }
            $docs[] = [
                'id'           => "{$post->id}_{$locale}",
                'post_id'      => $post->id,
                'language'     => $locale,
                'title'        => (string) $title,
                'content'      => strip_tags((string) $content),
                'excerpt'      => (string) $excerpt,
                'slug'         => $post->getLocaleSlug($locale),
                'subtype'      => $post->subtype,
                'status'       => $post->status,
                'is_featured'  => (bool) $post->is_featured,
                'tags'         => $tagSlugs,
                'published_at' => $post->published_at?->timestamp,
            ];
        }

        if (! empty($docs)) {
            $index->addDocuments($docs);
        }
    }

    public function delete(int $postId): void
    {
        $index = $this->client->index($this->indexName());
        try {
            $index->deleteDocuments(['filter' => "post_id = {$postId}"]);
        } catch (\Throwable) {
            foreach (Language::where('status', true)->pluck('a2_iso') as $loc) {
                try {
                    $index->deleteDocument("{$postId}_{$loc}");
                } catch (\Throwable) {
                }
            }
        }
    }

    public function search(string $query, string $locale, int $limit = 20): Collection
    {
        $index = $this->client->index($this->indexName());

        $result = $index->search($query, [
            'filter' => ["language = {$locale}", "status = published"],
            'limit'  => $limit,
        ]);

        return collect($result->getHits());
    }
}
