"""Base class for Handshakes."""

import asyncio
from abc import ABC, abstractmethod
from typing import (
    Any,
    Sequence,
    Union,
)

from chonkie.logger import get_logger
from chonkie.types import Chunk

logger = get_logger(__name__)

# TODO: Move this to inside the BaseHandshake class
# Why is this even outside the class?
# def _generate_default_id(*args: Any) -> str:
#     """Generate a default UUID."""
#     return str(uuid.uuid4())


class BaseHandshake(ABC):
    """Abstract base class for Handshakes."""

    @abstractmethod
    def write(self, chunks: Union[Chunk, list[Chunk]]) -> Any:
        """Write chunk(s) to the vector database.

        Args:
            chunks (Union[Chunk, list[Chunk]]): The chunk(s) to write.

        Returns:
            Any: The result from the database write operation.

        """
        raise NotImplementedError

    async def awrite(self, chunk: Union[Chunk, list[Chunk]], **kwargs: Any) -> Any:
        """Write chunks to the vector database asynchronously.

        Args:
            chunk (Union[Chunk, list[Chunk]]): The chunk(s) to write.
            **kwargs: Additional keyword arguments.

        Returns:
            Any: The result from the database write operation.

        """
        return await asyncio.to_thread(self.write, chunk, **kwargs)

    def __call__(self, chunks: Union[Chunk, list[Chunk]]) -> Any:
        """Write chunks using the default batch method when the instance is called.

        Args:
            chunks (Union[Chunk, list[Chunk]]): A single chunk or a sequence of chunks.

        Returns:
            Any: The result from the database write operation.

        """
        if isinstance(chunks, Chunk) or isinstance(chunks, Sequence):
            chunk_count = 1 if isinstance(chunks, Chunk) else len(chunks)
            logger.info(
                f"Writing {chunk_count} chunk(s) to database with {self.__class__.__name__}",
            )
            try:
                result = self.write(chunks)
                logger.debug(f"Successfully wrote {chunk_count} chunk(s)")
                return result
            except Exception as e:
                logger.error(
                    f"Failed to write {chunk_count} chunk(s) to database: {e}",
                    exc_info=True,
                )
                raise
        else:
            raise TypeError("Input must be a Chunk or a sequence of Chunks.")
