import streamlit as st
import requests
from bs4 import BeautifulSoup
import os
import docx
from PIL import Image
import io
import pytesseract
from pdf2image import convert_from_path
import random
import tempfile
import shutil
from concurrent.futures import ThreadPoolExecutor, as_completed

# Устанавливаем путь к исполняемому файлу Tesseract OCR
pytesseract.pytesseract.tesseract_cmd = r"/usr/bin/tesseract"  # Укажите путь к tesseract в вашей системе

# Настройка заголовка приложения
st.set_page_config(page_title="Система обработки учебных материалов", layout="wide")
st.title("Система обработки учебных материалов")

# Функция поиска учебников
def search_textbooks(keywords, year):
    # Используем Open Library Search API
    base_url = "http://openlibrary.org/search.json"
    params = {
        'title': keywords,
        'language': 'rus',
        'published_in': str(year)
    }
    try:
        response = requests.get(base_url, params=params, timeout=10)
        response.raise_for_status()
    except requests.RequestException as e:
        st.error(f"Ошибка при поиске учебников: {e}")
        return []

    data = response.json()
    textbooks = []
    for doc in data.get('docs', []):
        title = doc.get('title')
        authors = doc.get('author_name', [])
        publish_year = doc.get('first_publish_year')
        if title and publish_year and publish_year >= year:
            textbooks.append({
                'title': title,
                'authors': ", ".join(authors),
                'year': publish_year,
                'url': f"http://openlibrary.org{doc.get('key')}"
            })
    return textbooks

# Кэшируем процесс конвертации PDF в DOCX
@st.cache_data(show_spinner=False)
def convert_to_doc(file):
    try:
        with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp_file:
            tmp_file.write(file.read())
            tmp_file_path = tmp_file.name

        # Конвертация PDF в изображения с высоким DPI
        images = convert_from_path(tmp_file_path, dpi=300)

        def process_image(image):
            return pytesseract.image_to_string(image, lang='rus')

        # Параллельная обработка изображений для ускорения OCR
        with ThreadPoolExecutor(max_workers=4) as executor:
            text_parts = list(executor.map(process_image, images))

        text = "\n".join(text_parts)

        # Создание DOCX файла из извлеченного текста
        doc = docx.Document()
        doc.add_paragraph(text)
        output_path = os.path.join(tempfile.gettempdir(), f"converted_{random.randint(1000,9999)}.docx")
        doc.save(output_path)
        return output_path
    except Exception as e:
        st.error(f"Ошибка при конвертации: {e}")
        return None
    finally:
        if 'tmp_file_path' in locals():
            try:
                os.unlink(tmp_file_path)
            except Exception:
                pass

# Оптимизированная функция для разделения на главы
@st.cache_data(show_spinner=False)
def split_into_chapters(doc_file):
    try:
        doc = docx.Document(doc_file)
        chapters = []
        current_chapter = []

        total_paragraphs = len(doc.paragraphs)
        if total_paragraphs == 0:
            st.error("Документ не содержит параграфов.")
            return []

        for idx, para in enumerate(doc.paragraphs, 1):
            if para.style.name.startswith('Heading'):
                if current_chapter:
                    chapters.append("\n".join(current_chapter))
                    current_chapter = []
            current_chapter.append(para.text)

            # Обновляем прогресс каждые 500 параграфов
            if idx % 500 == 0 or idx == total_paragraphs:
                progress = idx / total_paragraphs
                st.progress(min(progress, 0.95))  # Оставляем небольшой зазор до 100%

        if current_chapter:
            chapters.append("\n".join(current_chapter))

        st.progress(1.0)  # Обозначаем завершение процесса
        return chapters
    except Exception as e:
        st.error(f"Ошибка при разделении на главы: {e}")
        return []

# Функция для генерации тестовых вопросов
def generate_test(chapters, num_questions_per_chapter):
    questions = []
    for idx, chapter in enumerate(chapters):
        # Разбиваем текст главы на предложения
        sentences = chapter.split('.')
        sentences = [s.strip() for s in sentences if len(s.strip()) > 20]
        random.shuffle(sentences)
        # Извлекаем первые N предложений для создания вопросов
        for i in range(min(num_questions_per_chapter, len(sentences))):
            sentence = sentences[i]
            question = f"Что подразумевается под следующим утверждением: '{sentence}'?"
            questions.append((f"Глава {idx+1}", question))
    return questions

# Интерфейс поиска учебников
st.header("1. Поиск учебников")
keywords = st.text_input("Введите ключевые слова для поиска:")
year = st.number_input("Минимальный год издания:", min_value=1900, max_value=2023, value=2019)
if st.button("Поиск"):
    with st.spinner("Идет поиск учебников..."):
        results = search_textbooks(keywords, year)
    st.write("Результаты поиска:")
    if results:
        for book in results:
            st.markdown(f"**{book['title']}**")
            st.write(f"Авторы: {book['authors']}")
            st.write(f"Год издания: {book['year']}")
            st.write(f"[Перейти к источнику]({book['url']})")
            st.write("---")
    else:
        st.write("Учебники не найдены. Попробуйте изменить параметры поиска.")

# Оптимизированный интерфейс загрузки и обработки файлов
st.header("2. Загрузка и обработка файлов")
uploaded_file = st.file_uploader("Выберите PDF файл для загрузки", type=["pdf"])
if uploaded_file is not None:
    st.write(f"Файл **{uploaded_file.name}** успешно загружен")
    if st.button("Конвертировать и обработать файл"):
        # Создаем контейнеры для прогресса и статуса
        progress_bar = st.progress(0)
        status_text = st.empty()

        # Конвертация файла
        status_text.text("Конвертация PDF в DOCX...")
        with st.spinner("Конвертация PDF в DOCX..."):
            doc_file = convert_to_doc(uploaded_file)
        
        if doc_file:
            st.success("Конвертация завершена.")
            status_text.text("Разделение на главы...")
            # Разделение на главы
            with st.spinner("Разделение на главы..."):
                chapters = split_into_chapters(doc_file)
            
            if chapters:
                st.success("Документ успешно разделен на главы.")
                st.write("Файл разделен на главы:")
                for i, chapter in enumerate(chapters, 1):
                    st.markdown(f"### Глава {i}")
                    # Безопасно отображаем первые 500 символов
                    display_text = (chapter[:500] + "...") if len(chapter) > 500 else chapter
                    st.write(display_text)
            else:
                st.error("Не удалось разделить документ на главы.")
        else:
            st.error("Не удалось конвертировать файл.")

# Интерфейс генерации тестов
st.header("3. Генерация тестов")
# Используем сессионное состояние для хранения глав
if 'chapters' not in st.session_state:
    st.session_state.chapters = []

if uploaded_file is not None and 'chapters' not in st.session_state:
    if st.button("Конвертировать и обработать файл"):
        with st.spinner("Обработка файла..."):
            doc_file = convert_to_doc(uploaded_file)
            if doc_file:
                chapters = split_into_chapters(doc_file)
                st.session_state.chapters = chapters

if st.session_state.chapters:
    num_questions = st.slider("Выберите количество вопросов на главу:", min_value=1, max_value=10, value=5)
    if st.button("Сгенерировать тест"):
        with st.spinner("Генерация тестовых вопросов..."):
            questions = generate_test(st.session_state.chapters, num_questions)
        if questions:
            st.write("Сгенерированные вопросы:")
            for chapter_title, question in questions:
                st.markdown(f"**{chapter_title}**")
                st.write(question)
                st.write("---")
            # Сохраняем вопросы в файл
            test_doc = docx.Document()
            test_doc.add_heading("Тестовые вопросы", level=1)
            for chapter_title, question in questions:
                test_doc.add_paragraph(f"{chapter_title}\n{question}")
            test_doc_path = os.path.join(tempfile.gettempdir(), f"test_questions_{random.randint(1000,9999)}.docx")
            test_doc.save(test_doc_path)
            with open(test_doc_path, "rb") as f:
                st.download_button(
                    label="Скачать файл с вопросами",
                    data=f,
                    file_name="test_questions.docx",
                    mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document"
                )
        else:
            st.error("Не удалось сгенерировать вопросы.")
else:
    st.info("Сначала загрузите и обработайте файл для генерации тестов.")

# Дополнительная информация
st.sidebar.header("О приложении")
st.sidebar.info(
    "Это система обработки учебных материалов. Вы можете искать учебники, загружать и обрабатывать свои файлы, а также генерировать тестовые вопросы на основе содержимого."
) оптимизируй масимально разделение пдф файла на главы и чтобы скрипт контролировал загрузку памяти и не превышал