"""
Azure AI Search 관련자료 DB
"""
from azure.core.credentials import AzureKeyCredential
from azure.search.documents import SearchClient
from azure.search.documents.indexes import SearchIndexClient
from azure.search.documents.indexes.models import (
    SearchIndex,
    SimpleField,
    SearchableField,
    SearchField,
    VectorSearch,
    HnswAlgorithmConfiguration,
    VectorSearchProfile,
    SemanticConfiguration,
    SemanticField,
    SemanticPrioritizedFields,
    SemanticSearch,
    SearchFieldDataType
)
from azure.search.documents.models import (
    VectorizedQuery,
    QueryType,
    QueryCaptionType,
    QueryAnswerType
)
from typing import List, Dict, Any, Optional
import logging

from ..models.document import DocumentChunk

logger = logging.getLogger(__name__)


class AzureAISearchDB:
    """Azure AI Search 관련자료 데이터베이스"""

    def __init__(
        self,
        endpoint: str,
        api_key: str,
        index_name: str = "meeting-minutes-index",
        api_version: str = "2023-11-01"
    ):
        """
        초기화

        Args:
            endpoint: Azure AI Search 엔드포인트
            api_key: API 키
            index_name: 인덱스 이름
            api_version: API 버전
        """
        self.endpoint = endpoint
        self.api_key = api_key
        self.index_name = index_name

        credential = AzureKeyCredential(api_key)
        self.search_client = SearchClient(
            endpoint=endpoint,
            index_name=index_name,
            credential=credential
        )
        self.index_client = SearchIndexClient(
            endpoint=endpoint,
            credential=credential
        )

    def create_index(self):
        """
        인덱스 생성 (스키마 정의)
        """
        # 필드 정의
        fields = [
            SimpleField(name="id", type=SearchFieldDataType.String, key=True),
            SimpleField(name="documentId", type=SearchFieldDataType.String, filterable=True),
            SimpleField(name="documentType", type=SearchFieldDataType.String, filterable=True, facetable=True),
            SearchableField(name="title", type=SearchFieldDataType.String, analyzer_name="ko.lucene"),
            SimpleField(name="folder", type=SearchFieldDataType.String, filterable=True, facetable=True),
            SimpleField(name="createdDate", type=SearchFieldDataType.DateTimeOffset, filterable=True, sortable=True),
            SearchField(
                name="participants",
                type=SearchFieldDataType.Collection(SearchFieldDataType.String),
                searchable=True,
                filterable=True,
                facetable=True
            ),
            SearchField(
                name="keywords",
                type=SearchFieldDataType.Collection(SearchFieldDataType.String),
                searchable=True,
                facetable=True
            ),
            SimpleField(name="agendaId", type=SearchFieldDataType.String, filterable=True),
            SearchableField(name="agendaTitle", type=SearchFieldDataType.String, analyzer_name="ko.lucene"),
            SimpleField(name="chunkIndex", type=SearchFieldDataType.Int32, filterable=True, sortable=True),
            SearchableField(name="content", type=SearchFieldDataType.String, analyzer_name="ko.lucene"),
            SearchField(
                name="contentVector",
                type=SearchFieldDataType.Collection(SearchFieldDataType.Single),
                searchable=True,
                vector_search_dimensions=1536,
                vector_search_profile_name="meeting-vector-profile"
            ),
            SimpleField(name="tokenCount", type=SearchFieldDataType.Int32, filterable=True)
        ]

        # 벡터 검색 설정
        vector_search = VectorSearch(
            profiles=[
                VectorSearchProfile(
                    name="meeting-vector-profile",
                    algorithm_configuration_name="meeting-hnsw"
                )
            ],
            algorithms=[
                HnswAlgorithmConfiguration(
                    name="meeting-hnsw",
                    parameters={
                        "m": 4,
                        "efConstruction": 400,
                        "efSearch": 500,
                        "metric": "cosine"
                    }
                )
            ]
        )

        # Semantic Search 설정
        semantic_config = SemanticConfiguration(
            name="meeting-semantic-config",
            prioritized_fields=SemanticPrioritizedFields(
                title_field=SemanticField(field_name="title"),
                content_fields=[SemanticField(field_name="content")],
                keywords_fields=[SemanticField(field_name="keywords")]
            )
        )

        semantic_search = SemanticSearch(
            configurations=[semantic_config]
        )

        # 인덱스 생성
        index = SearchIndex(
            name=self.index_name,
            fields=fields,
            vector_search=vector_search,
            semantic_search=semantic_search
        )

        try:
            self.index_client.create_or_update_index(index)
            logger.info(f"Azure AI Search 인덱스 생성 완료: {self.index_name}")
        except Exception as e:
            logger.error(f"인덱스 생성 실패: {str(e)}")
            raise

    def upload_documents(self, chunks: List[DocumentChunk]) -> bool:
        """
        문서 업로드 (배치)

        Args:
            chunks: 문서 청크 리스트

        Returns:
            성공 여부
        """
        if not chunks:
            return True

        try:
            # Pydantic 모델을 딕셔너리로 변환
            documents = [chunk.dict() for chunk in chunks]

            # 배치 업로드 (최대 1000개씩)
            batch_size = 1000
            for i in range(0, len(documents), batch_size):
                batch = documents[i:i + batch_size]
                result = self.search_client.upload_documents(documents=batch)

                logger.info(f"배치 {i//batch_size + 1}: {len(batch)}개 문서 업로드 완료")

            return True

        except Exception as e:
            logger.error(f"문서 업로드 실패: {str(e)}")
            return False

    def hybrid_search(
        self,
        query: str,
        query_embedding: List[float],
        top_k: int = 3,
        folder: Optional[str] = None,
        document_type: Optional[str] = None,
        semantic_ranking: bool = True
    ) -> List[Dict[str, Any]]:
        """
        Hybrid Search (Keyword + Vector + Semantic Ranking)

        Args:
            query: 검색 쿼리
            query_embedding: 쿼리 임베딩 벡터
            top_k: 반환할 최대 결과 수
            folder: 폴더 필터
            document_type: 문서 타입 필터
            semantic_ranking: Semantic Ranking 사용 여부

        Returns:
            검색 결과 리스트
        """
        try:
            # Vector Query
            vector_query = VectorizedQuery(
                vector=query_embedding,
                k_nearest_neighbors=50,
                fields="contentVector"
            )

            # 필터 생성
            filter_parts = []
            if folder:
                filter_parts.append(f"folder eq '{folder}'")
            if document_type:
                filter_parts.append(f"documentType eq '{document_type}'")

            filter_expression = " and ".join(filter_parts) if filter_parts else None

            # 검색 옵션 설정
            search_params = {
                "search_text": query,
                "vector_queries": [vector_query],
                "select": ["documentId", "title", "createdDate", "content", "agendaTitle", "folder"],
                "top": 50 if semantic_ranking else top_k,
                "filter": filter_expression
            }

            # Semantic Ranking 활성화
            if semantic_ranking:
                search_params.update({
                    "query_type": QueryType.SEMANTIC,
                    "semantic_configuration_name": "meeting-semantic-config",
                    "query_caption": QueryCaptionType.EXTRACTIVE,
                    "query_answer": QueryAnswerType.EXTRACTIVE
                })

            # 검색 실행
            results = self.search_client.search(**search_params)

            # 결과 처리
            search_results = []
            for i, result in enumerate(results):
                if i >= top_k:
                    break

                # Reranking Score (Semantic Ranking 또는 BM25 Score)
                score = result.get("@search.reranker_score", result.get("@search.score", 0.0))

                # 관련도 레벨 결정
                if score >= 3.0:  # Semantic Ranking 점수 기준
                    relevance_level = "HIGH"
                elif score >= 2.0:
                    relevance_level = "MEDIUM"
                else:
                    relevance_level = "LOW"

                # Caption 추출 (Semantic Captions)
                captions = result.get("@search.captions", [])
                excerpt = captions[0].text if captions else result["content"][:300]

                search_results.append({
                    "document_id": result["documentId"],
                    "title": result["title"],
                    "document_type": result.get("documentType", "unknown"),
                    "created_date": result.get("createdDate"),
                    "relevance_score": min(score / 4.0, 1.0),  # 0~1 정규화
                    "relevance_level": relevance_level,
                    "content_excerpt": excerpt,
                    "folder": result.get("folder")
                })

            return search_results

        except Exception as e:
            logger.error(f"Hybrid Search 실패: {str(e)}")
            return []

    def delete_documents_by_id(self, document_id: str) -> bool:
        """
        문서 ID로 모든 청크 삭제

        Args:
            document_id: 문서 ID

        Returns:
            성공 여부
        """
        try:
            # 해당 문서의 모든 청크 조회
            results = self.search_client.search(
                search_text="*",
                filter=f"documentId eq '{document_id}'",
                select=["id"]
            )

            # 청크 ID 수집
            chunk_ids = [{"id": result["id"]} for result in results]

            if chunk_ids:
                # 배치 삭제
                self.search_client.delete_documents(documents=chunk_ids)
                logger.info(f"문서 {document_id}의 {len(chunk_ids)}개 청크 삭제 완료")

            return True

        except Exception as e:
            logger.error(f"문서 삭제 실패 ({document_id}): {str(e)}")
            return False

    def get_stats(self) -> Dict[str, Any]:
        """
        인덱스 통계 조회

        Returns:
            통계 정보
        """
        try:
            # 전체 문서 수 (중복 제거)
            results = self.search_client.search(
                search_text="*",
                select=["documentId", "documentType"],
                top=10000
            )

            document_ids = set()
            type_counts = {}

            for result in results:
                doc_id = result.get("documentId")
                doc_type = result.get("documentType", "unknown")

                if doc_id:
                    document_ids.add(doc_id)

                type_counts[doc_type] = type_counts.get(doc_type, 0) + 1

            return {
                "total_documents": len(document_ids),
                "total_chunks": sum(type_counts.values()),
                "by_type": type_counts
            }

        except Exception as e:
            logger.error(f"통계 조회 실패: {str(e)}")
            return {
                "total_documents": 0,
                "total_chunks": 0,
                "by_type": {}
            }
