# -*- coding: utf-8 -*-
"""NHÚNG — giao diện vector, có bản rỗng dùng mặc định.

VÌ SAO tách riêng giao diện thay vì gọi thẳng sentence_transformers ở nơi
cần vector: kho tri thức lúc mới dựng CHƯA CHỌN mô hình nhúng nào (chưa rõ
chi phí VPS chạy nổi model nào, chưa có ngân sách API). Nếu chi_muc.py gọi
thẳng thư viện, dựng chỉ mục lần đầu sẽ hỏng ngay vì thiếu dependency. Tách
ra BoNhung + bản NhungRong thì chỉ mục dựng được NGAY BÂY GIỜ, chạy thuần
BM25 (xem tim/bm25.py) — chừng nào chọn xong mô hình mới đổi MỘT dòng thay
bo_nhung, không phải sửa chi_muc.py hay cat_doan.py.

VÌ SAO không cần cơ sở dữ liệu vector (Faiss, Milvus, pgvector...): kho chỉ
~500 đoạn. Nhân ma trận vài trăm x vài trăm chiều trong bộ nhớ mất vài mili
giây — mọi hạ tầng vector DB chuyên dụng ở quy mô này chỉ thêm chỗ để hỏng
(một tiến trình nữa cần chạy, một phiên bản nữa cần khớp) mà không đổi lấy
tốc độ nào đo được. Vector (nếu có) nhét thẳng vào cột BLOB trong CÙNG tệp
SQLite với văn bản — một tệp, không hai hệ thống phải đồng bộ với nhau.
"""
from __future__ import annotations

from typing import List


class BoNhung:
    """Giao diện bắt buộc của một bộ nhúng vector."""

    so_chieu: int = 0

    def nhung(self, cac_van_ban: List[str]) -> List[List[float]]:
        raise NotImplementedError


class NhungRong(BoNhung):
    """Bản rỗng — dùng khi chưa chọn mô hình nhúng.

    Trả về vector rỗng [] cho mọi văn bản, so_chieu = 0. chi_muc.py và tầng
    tìm kiếm đọc so_chieu để biết có vector hay không và bỏ qua nhánh
    vector — tìm kiếm khi đó chạy THUẦN BM25, không phải một chế độ lỗi.
    """

    so_chieu = 0

    def nhung(self, cac_van_ban: List[str]) -> List[List[float]]:
        return [[] for _ in cac_van_ban]


class NhungSentenceTransformers(BoNhung):
    """Bản thật, dùng sentence-transformers.

    VÌ SAO import trễ (trong __init__, không phải đầu tệp): sentence-
    transformers kéo theo torch — vài trăm MB, cài chậm, và một VPS chỉ
    chạy BM25 (NhungRong) không có lý do gì phải cài nó. Import ở đầu tệp
    sẽ làm CẢ MODULE nhung.py hỏng ngay khi thiếu thư viện, kể cả khi
    người dùng chỉ cần mỗi NhungRong.

    VÌ SAO mặc định 'BAAI/bge-m3': đa ngôn ngữ (kho có cả bản Việt lẫn
    Anh trong cùng một Doan), và là một trong số ít model nhúng đa ngôn
    ngữ hiện có phần dịch/huấn luyện tốt cho tiếng Việt — nhiều model
    embedding tiếng Anh thuần chấm điểm tiếng Việt rất kém vì gần như
    không thấy dữ liệu Việt lúc huấn luyện.
    """

    def __init__(self, ten_model: str = 'BAAI/bge-m3'):
        try:
            from sentence_transformers import SentenceTransformer
        except ImportError as loi:
            raise RuntimeError(
                "Chưa cài sentence-transformers. Cài bằng:\n"
                "    pip install sentence-transformers\n"
                "(sẽ kéo theo torch, có thể mất vài phút và vài trăm MB — "
                "chỉ cần khi thật sự muốn bật tìm kiếm theo vector, còn "
                "không thì cứ dùng NhungRong, tìm kiếm vẫn chạy tốt bằng "
                "BM25 thuần)."
            ) from loi

        self._model = SentenceTransformer(ten_model)
        # so_chieu đọc thẳng từ model thay vì hard-code theo tên, vì đổi
        # ten_model (thử model khác) không cần sửa thêm chỗ nào khác.
        self.so_chieu = self._model.get_sentence_embedding_dimension()

    def nhung(self, cac_van_ban: List[str]) -> List[List[float]]:
        if not cac_van_ban:
            return []
        vector = self._model.encode(cac_van_ban, normalize_embeddings=True)
        # .tolist() để trả kiểu chuẩn Python (list[list[float]]) đúng giao
        # diện BoNhung — không bắt nơi gọi phải biết numpy/torch tồn tại.
        return vector.tolist()
