import re
import logging
import time
from fastapi import FastAPI, HTTPException, Response
from prometheus_client import Histogram, Counter, generate_latest
from prometheus_client.exposition import CONTENT_TYPE_LATEST
from pydantic import BaseModel

from bs4 import BeautifulSoup
from markdownify import markdownify

class MetricsLogFilter(logging.Filter):
    """Фильтр для исключения логов метрик из access логов"""
    
    def filter(self, record):
        if hasattr(record, 'args') and record.args and len(record.args) >= 3:
            request_path = record.args[2]
            if '/metrics' in request_path:
                return False
        return True

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',
)
logger = logging.getLogger(__name__)

uvicorn_access_logger = logging.getLogger("uvicorn.access")
uvicorn_access_logger.addFilter(MetricsLogFilter())

app = FastAPI()

PROCESSING_TIME = Histogram(
    "page_parser_document_processing_seconds",
    "Время обработки файла в секундах",
    buckets=[0.1, 0.5, 1.0, 2.0, 5.0, 10.0]
)
PROCESSING_COUNT = Counter(
    "page_parser_document_processing_count",
    "Количество обработанных файлов",
    ["status"]
)

class ParserRequest(BaseModel):
    raw_content: str

class ParserResponse(BaseModel):
    parsed_content: str

@app.get("/metrics")
async def metrics():
    """Возвращает метрики в формате Prometheus"""
    return Response(generate_latest(), media_type=CONTENT_TYPE_LATEST)

@app.post("/parsed_text", response_model=ParserResponse)
async def parsed_text(request: ParserRequest) -> ParserResponse:
    """Парсит текст с html тегами в markdown"""
    start_time = time.time()
    processing_success = False
    try:
        text = request.raw_content
        logger.info(f"Документ принят в работу: {text[:50]}")
        parsed_text = html_to_markdown(text)
        logger.info(f"Документ успешно обработан: {parsed_text[:50]}")

        processing_success = True
        return ParserResponse(parsed_content=parsed_text)
    except Exception as e:
        logger.error(f"Общая ошибка при парсинге: {str(e)}")
        raise HTTPException(status_code=500, detail=f"Ошибка при парсинге: {str(e)}")
    finally:
        PROCESSING_TIME.observe(time.time() - start_time)
        status = "success" if processing_success else "error"
        PROCESSING_COUNT.labels(status=status).inc()


def remove_external_links(markdown_text: str) -> str:
    """Удаляет внешние ссылки из markdown текста."""
    link_pattern = r'\[([^\]]+)\]\(([^)]+)\)'
    processed_text = re.sub(link_pattern, r'\1', markdown_text)
    
    # Удаляем <http://example.com> ссылки
    url_pattern_1 = r'<(https?://[^>]+)>'
    processed_text = re.sub(url_pattern_1, '', processed_text)
    
    # Удаляем обычные URL
    url_pattern_2 = r'https?://[^\s]+[\w](?=[.,;:!?]?(?:\s|$))'
    processed_text = re.sub(url_pattern_2, '', processed_text)
    
    return processed_text

def html_to_markdown(html_content: str) -> str:
    """Конвертация HTML в Markdown с улучшенной очисткой."""
    try:
        # Удаляем навигационные элементы
        soup = BeautifulSoup(html_content, 'html.parser')
        
        # Удаляем различные навигационные элементы
        for nav in soup.find_all(['nav', 'div'], {'class': re.compile('.*nav.*')}):
            nav.decompose()
        
        for nav in soup.find_all(id=re.compile('.*navigation.*')):
            nav.decompose()
            
        # Удаляем скрипты и стили
        for script in soup.find_all(['script', 'style']):
            script.decompose()
        
        # Получаем очищенный HTML
        cleaned_html = str(soup)
        
        # Конвертируем в markdown
        markdown_content = markdownify(
            cleaned_html,
            heading_style="ATX"
        ).strip()
        
        # Удаляем внешние ссылки
        markdown_content = remove_external_links(markdown_content)
        
        logger.debug(f'HTML успешно конвертирован в Markdown, длина: {len(markdown_content)} символов')
        return markdown_content
        
    except Exception as e:
        logger.error(f'Ошибка конвертации HTML в Markdown: {str(e)}')
        raise Exception(f"Ошибка конвертации HTML в Markdown: {str(e)}")

