<?php

declare(strict_types=1);

namespace Mtc\Plugins\Agent\Agents\VectorStore;

use GuzzleHttp\Client;
use GuzzleHttp\RequestOptions;
use Illuminate\Support\Facades\Log;
use NeuronAI\RAG\Document;
use NeuronAI\RAG\VectorStore\VectorStoreInterface;

class PineconeVectorStore implements VectorStoreInterface
{
    protected Client $client;

    protected array $filters = [];

    public function __construct(
        string $key,
        protected string $indexUrl,
        protected int $topK = 4,
        string $version = '2025-04',
        protected string $namespace = '__default__'
    ) {
        $this->client = new Client([
            'base_uri' => \trim($this->indexUrl, '/').'/',
            'headers' => [
                'Accept' => 'application/json',
                'Content-Type' => 'application/json',
                'Api-Key' => $key,
                'X-Pinecone-API-Version' => $version,
            ]
        ]);
    }

    public function addDocument(Document $document): VectorStoreInterface
    {
        return $this->addDocuments([$document]);
    }

    public function addDocuments(array $documents): VectorStoreInterface
    {
        $this->client->post("vectors/upsert", [
            RequestOptions::JSON => [
                'namespace' => $this->namespace,
                'vectors' => \array_map(fn (Document $document): array => [
                    'id' => (string) $document->getId(),
                    'values' => $document->getEmbedding(),
                    'metadata' => [
                        'content' => $document->getContent(),
                        'sourceType' => $document->getSourceType(),
                        'sourceName' => $document->getSourceName(),
                        ...$document->metadata,
                    ],
                ], $documents)
            ]
        ]);

        return $this;
    }

    public function deleteBySource(string $sourceType, string $sourceName): VectorStoreInterface
    {
        $this->client->post("vectors/delete", [
            RequestOptions::JSON => [
                'namespace' => $this->namespace,
                'filter' => [
                    'sourceType' => ['$eq' => $sourceType],
                    'sourceName' => ['$eq' => $sourceName],
                ]
            ]
        ]);

        return $this;
    }

    public function similaritySearch(array $embedding): iterable
    {
        $payload = [
            'namespace' => $this->namespace,
            'includeMetadata' => true,
            'includeValues' => true,
            'vector' => $embedding,
            'topK' => $this->topK,
        ];

        // Only include filter if it's not empty
        if (!empty($this->filters)) {
            $payload['filter'] = $this->filters;
        }

        Log::info('Pinecone: Searching vector DB', [
            'namespace' => $this->namespace,
            'topK' => $this->topK,
            'embedding_length' => count($embedding),
        ]);

        $result = $this->client->post("query", [
            RequestOptions::JSON => $payload
        ])->getBody()->getContents();

        $result = \json_decode($result, true);

        Log::info('Pinecone: Search results', [
            'matches_count' => count($result['matches'] ?? []),
            'matches' => array_map(fn($m) => [
                'id' => $m['id'],
                'score' => $m['score'],
                'content_preview' => substr($m['metadata']['content'] ?? '', 0, 100),
            ], $result['matches'] ?? []),
        ]);

        return \array_map(function (array $item): Document {
            $document = new Document();
            $document->id = $item['id'];
            $document->embedding = $item['values'];
            $document->content = $item['metadata']['content'];
            $document->sourceType = $item['metadata']['sourceType'];
            $document->sourceName = $item['metadata']['sourceName'];
            $document->score = $item['score'];

            foreach ($item['metadata'] as $name => $value) {
                if (!\in_array($name, ['content', 'sourceType', 'sourceName'])) {
                    $document->addMetadata($name, $value);
                }
            }

            return $document;
        }, $result['matches']);
    }

    public function withFilters(array $filters): self
    {
        $this->filters = $filters;
        return $this;
    }
}
