import json
import os
import time
import logging
from typing import List

import requests
from dotenv import load_dotenv
from fastapi import HTTPException
from langchain.text_splitter import RecursiveCharacterTextSplitter

logger = logging.getLogger(__name__)


def load_env() -> None:
    """Загрузка переменных окружения из .env файла."""
    load_dotenv()
    logger.debug('Переменные окружения загружены из .env файла')


def split_text_to_chunks(content: str, chunk_size: int, chunk_overlap: int) -> List[str]:
    """Разбивает текст на чанки."""
    if not content.strip():
        logger.warning('Пустой контент для разбивки на чанки')
        return []
        
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=chunk_size,
        chunk_overlap=chunk_overlap,
        separators=["\n\n", "\n", " ", ""]
    )
    
    chunks = text_splitter.split_text(content)
    logger.debug(f'Текст разбит на {len(chunks)} чанков')
    return chunks


def get_embeddings_batch(texts: List[str], model_name: str, api_url: str, max_retries: int = 3, retry_delay: int = 2) -> List[List[float]]:
    """Получает эмбеддинги для одного батча."""
    data = {
        "input": texts,
        "model": model_name
    }
    
    for attempt in range(max_retries):
        try:
            logger.debug(f'Запрос эмбеддингов для батча из {len(texts)} текстов, попытка {attempt + 1}')
            
            timeout = max(30, len(texts) * 2)  # минимум 30 сек, +2 сек на чанк
            
            response = requests.post(
                api_url, 
                headers={"Content-Type": "application/json"}, 
                data=json.dumps(data),
                timeout=timeout
            )
            
            if response.status_code == 200:
                embeddings = [elem['embedding'] for elem in response.json()['data']]
                logger.debug(f'Получено {len(embeddings)} эмбеддингов для батча')
                return embeddings
            elif response.status_code == 429:
                wait_time = retry_delay * (attempt + 1)
                logger.warning(f"Ограничение запросов API для батча, ожидание {wait_time} сек...")
                time.sleep(wait_time)
            else:
                logger.error(f"Ошибка API для батча: {response.status_code}, {response.text}")
                if attempt == max_retries - 1:
                    raise HTTPException(status_code=response.status_code, detail=f"API ошибка: {response.text}")
                time.sleep(retry_delay)
                
        except requests.exceptions.RequestException as e:
            logger.error(f"Исключение при вызове API для батча: {str(e)}")
            if attempt == max_retries - 1:
                raise HTTPException(status_code=500, detail=f"Ошибка соединения с API: {str(e)}")
            time.sleep(retry_delay)
    
    # Если все попытки неудачны, возвращаем пустые векторы
    raise HTTPException(status_code=500, detail=f"Не удалось получить эмбеддинги после {max_retries} попыток")


def get_embeddings_from_api(texts: List[str], vector_dim: int, batch_size: int = 20, max_retries: int = 3, retry_delay: int = 2) -> List[List[float]]:
    """Получает эмбеддинги через API с батчевой обработкой."""
    api_url = os.getenv('URL_EMBEDDER')
    model_name = "deepvk/USER-bge-m3"
    
    if not api_url:
        logger.error('Не задана переменная окружения URL_EMBEDDER')
        raise HTTPException(status_code=500, detail="URL_EMBEDDER не настроен")
    
    if not texts:
        logger.warning('Пустой список текстов для получения эмбеддингов')
        return []
    
    logger.info(f'Начинаем получение эмбеддингов для {len(texts)} текстов батчами по {batch_size}')
    
    all_embeddings = []
    total_batches = (len(texts) + batch_size - 1) // batch_size
    
    for i in range(0, len(texts), batch_size):
        batch_num = (i // batch_size) + 1
        batch_texts = texts[i:i + batch_size]
        
        logger.info(f'Обрабатываем батч {batch_num}/{total_batches} ({len(batch_texts)} чанков)')
        
        try:
            batch_embeddings = get_embeddings_batch(
                batch_texts, 
                model_name, 
                api_url, 
                max_retries, 
                retry_delay
            )
            all_embeddings.extend(batch_embeddings)
            
            # Небольшая пауза между батчами для снижения нагрузки на API
            if i + batch_size < len(texts):  # не последний батч
                time.sleep(0.5)
                
        except Exception as e:
            logger.error(f"Ошибка при обработке батча {batch_num}: {str(e)}")
            # Можно добавить fallback - пустые векторы для этого батча
            fallback_embeddings = [[0.0] * vector_dim for _ in range(len(batch_texts))]
            all_embeddings.extend(fallback_embeddings)
            logger.warning(f"Использованы пустые векторы для батча {batch_num}")
    
    logger.info(f'Завершено получение эмбеддингов: {len(all_embeddings)} векторов')
    return all_embeddings