# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

"""Builder to build full-text search."""

from abc import ABC, abstractmethod
from typing import Optional

from pypaimon.globalindex.global_index_result import GlobalIndexResult
from pypaimon.table.source.full_text_read import FullTextRead, FullTextReadImpl
from pypaimon.table.source.full_text_scan import FullTextScan, FullTextScanImpl


class FullTextSearchBuilder(ABC):
    """Builder to build full-text search."""

    @abstractmethod
    def with_limit(self, limit: int) -> 'FullTextSearchBuilder':
        """The top k results to return."""
        pass

    @abstractmethod
    def with_text_column(self, name: str) -> 'FullTextSearchBuilder':
        """The text column to search."""
        pass

    @abstractmethod
    def with_query_text(self, query_text: str) -> 'FullTextSearchBuilder':
        """The query text to search."""
        pass

    @abstractmethod
    def with_query_operator(self, query_operator: str) -> 'FullTextSearchBuilder':
        """The default operator for query terms. Supported values are 'or' and 'and'."""
        pass

    @abstractmethod
    def new_full_text_scan(self) -> FullTextScan:
        """Create full-text scan to scan index files."""
        pass

    @abstractmethod
    def new_full_text_read(self) -> FullTextRead:
        """Create full-text read to read index files."""
        pass

    def execute_local(self) -> GlobalIndexResult:
        """Execute full-text index search in local."""
        return self.new_full_text_read().read_plan(self.new_full_text_scan().scan())


class FullTextSearchBuilderImpl(FullTextSearchBuilder):
    """Implementation for FullTextSearchBuilder."""

    def __init__(self, table: 'FileStoreTable'):
        self._table = table
        self._limit: int = 0
        self._text_column: Optional['DataField'] = None
        self._query_text: Optional[str] = None
        self._query_operator: str = "or"

    def with_limit(self, limit: int) -> 'FullTextSearchBuilder':
        self._limit = limit
        return self

    def with_text_column(self, name: str) -> 'FullTextSearchBuilder':
        field_dict = {f.name: f for f in self._table.fields}
        if name not in field_dict:
            raise ValueError(f"Text column '{name}' not found in table schema")
        self._text_column = field_dict[name]
        return self

    def with_query_text(self, query_text: str) -> 'FullTextSearchBuilder':
        self._query_text = query_text
        return self

    def with_query_operator(self, query_operator: str) -> 'FullTextSearchBuilder':
        self._query_operator = query_operator
        return self

    def new_full_text_scan(self) -> FullTextScan:
        if self._text_column is None:
            raise ValueError("Text column must be set via with_text_column()")
        return FullTextScanImpl(self._table, self._text_column)

    def new_full_text_read(self) -> FullTextRead:
        if self._limit <= 0:
            raise ValueError("Limit must be positive, set via with_limit()")
        if self._text_column is None:
            raise ValueError("Text column must be set via with_text_column()")
        if self._query_text is None:
            raise ValueError("Query text must be set via with_query_text()")
        return FullTextReadImpl(
            self._table, self._limit, self._text_column,
            self._query_text, self._query_operator
        )
