import os
from typing import Optional

import pytest
from _pytest.monkeypatch import MonkeyPatch
from requests.adapters import HTTPAdapter
from tcvectordb import VectorDBClient  # type: ignore
from tcvectordb.model.database import Collection, Database  # type: ignore
from tcvectordb.model.document import Document, Filter  # type: ignore
from tcvectordb.model.enum import ReadConsistency  # type: ignore
from tcvectordb.model.index import Index  # type: ignore
from xinference_client.types import Embedding  # type: ignore


class MockTcvectordbClass:
    def mock_vector_db_client(
        self,
        url=None,
        username="",
        key="",
        read_consistency: ReadConsistency = ReadConsistency.EVENTUAL_CONSISTENCY,
        timeout=5,
        adapter: HTTPAdapter = None,
    ):
        self._conn = None
        self._read_consistency = read_consistency

    def list_databases(self) -> list[Database]:
        return [
            Database(
                conn=self._conn,
                read_consistency=self._read_consistency,
                name="dify",
            )
        ]

    def list_collections(self, timeout: Optional[float] = None) -> list[Collection]:
        return []

    def drop_collection(self, name: str, timeout: Optional[float] = None):
        return {"code": 0, "msg": "operation success"}

    def create_collection(
        self,
        name: str,
        shard: int,
        replicas: int,
        description: str,
        index: Index,
        embedding: Embedding = None,
        timeout: Optional[float] = None,
    ) -> Collection:
        return Collection(
            self,
            name,
            shard,
            replicas,
            description,
            index,
            embedding=embedding,
            read_consistency=self._read_consistency,
            timeout=timeout,
        )

    def describe_collection(self, name: str, timeout: Optional[float] = None) -> Collection:
        collection = Collection(self, name, shard=1, replicas=2, description=name, timeout=timeout)
        return collection

    def collection_upsert(
        self, documents: list[Document], timeout: Optional[float] = None, build_index: bool = True, **kwargs
    ):
        return {"code": 0, "msg": "operation success"}

    def collection_search(
        self,
        vectors: list[list[float]],
        filter: Filter = None,
        params=None,
        retrieve_vector: bool = False,
        limit: int = 10,
        output_fields: Optional[list[str]] = None,
        timeout: Optional[float] = None,
    ) -> list[list[dict]]:
        return [[{"metadata": '{"doc_id":"foo1"}', "text": "text", "doc_id": "foo1", "score": 0.1}]]

    def collection_query(
        self,
        document_ids: Optional[list] = None,
        retrieve_vector: bool = False,
        limit: Optional[int] = None,
        offset: Optional[int] = None,
        filter: Optional[Filter] = None,
        output_fields: Optional[list[str]] = None,
        timeout: Optional[float] = None,
    ) -> list[dict]:
        return [{"metadata": '{"doc_id":"foo1"}', "text": "text", "doc_id": "foo1", "score": 0.1}]

    def collection_delete(
        self,
        document_ids: Optional[list[str]] = None,
        filter: Filter = None,
        timeout: Optional[float] = None,
    ):
        return {"code": 0, "msg": "operation success"}


MOCK = os.getenv("MOCK_SWITCH", "false").lower() == "true"


@pytest.fixture
def setup_tcvectordb_mock(request, monkeypatch: MonkeyPatch):
    if MOCK:
        monkeypatch.setattr(VectorDBClient, "__init__", MockTcvectordbClass.mock_vector_db_client)
        monkeypatch.setattr(VectorDBClient, "list_databases", MockTcvectordbClass.list_databases)
        monkeypatch.setattr(Database, "collection", MockTcvectordbClass.describe_collection)
        monkeypatch.setattr(Database, "list_collections", MockTcvectordbClass.list_collections)
        monkeypatch.setattr(Database, "drop_collection", MockTcvectordbClass.drop_collection)
        monkeypatch.setattr(Database, "create_collection", MockTcvectordbClass.create_collection)
        monkeypatch.setattr(Collection, "upsert", MockTcvectordbClass.collection_upsert)
        monkeypatch.setattr(Collection, "search", MockTcvectordbClass.collection_search)
        monkeypatch.setattr(Collection, "query", MockTcvectordbClass.collection_query)
        monkeypatch.setattr(Collection, "delete", MockTcvectordbClass.collection_delete)

    yield

    if MOCK:
        monkeypatch.undo()
