import asyncio
import json
import os
from google.oauth2.service_account import Credentials
from googleapiclient.discovery import build
import logging
import traceback

class GoogleDocsProcessor:
    def __init__(self, credentials_file, max_concurrent_tasks=10, logger=None):
        """
        Инициализация процессора для работы с Google Docs.

        :param credentials_file: Путь к файлу с учетными данными Google API.
        :param max_concurrent_tasks: Максимальное количество одновременных задач.
        :param logger: Логгер, переданный из GoogleDocsCacheManager. Если None, логирование отключается.
        """
        self.credentials_file = credentials_file
        self.max_concurrent_tasks = max_concurrent_tasks

        # Настраиваем логгер
        self.logger = logger or logging.getLogger()
        if logger is None:
            self.logger.addHandler(logging.NullHandler())  # Отключаем логирование

        self.logger.info("✅ GoogleDocsProcessor успешно инициализирован.")

    def fetch_document_sync(self, document_id):
        """
        Синхронное получение содержимого документа Google Docs.

        :param document_id: ID документа Google Docs.
        :return: JSON-структура документа.
        """
        scopes = ['https://www.googleapis.com/auth/documents.readonly']
        creds = Credentials.from_service_account_file(self.credentials_file, scopes=scopes)
        service = build('docs', 'v1', credentials=creds)

        self.logger.debug("Загрузка документа %s", document_id)

        try:
            document = service.documents().get(documentId=document_id, includeTabsContent=True).execute()
            return {
                "document_id": document_id,
                "title": document.get("title", "Unknown title"),
                "tabs": document.get("tabs", [])  # Безопасное обращение к ключу
            }
        except Exception as e:
            self.logger.error("Ошибка при загрузке документа %s: %s", document_id, str(e))
            return {
                "document_id": document_id,
                "title": "Unknown title",
                "tabs": [],
                "status": {
                    "error_code": 2,
                    "error_message": traceback.format_exc()
                }
            }

    async def extract_tab_content(self, tab):
        """
        Извлечение текста из вкладки документа.

        :param tab: JSON-структура вкладки (tab).
        :return: Текст вкладки в виде строки.
        """
        content = tab.get('documentTab', {}).get('body', {}).get('content', []) or []
        return ''.join(
            text_element['textRun']['content']
            for element in content if 'paragraph' in element
            for text_element in element['paragraph'].get('elements', [])
            if 'textRun' in text_element
        )

    async def process_tabs(self, tabs):
        """
        Рекурсивная обработка вкладок и их преобразование в JSON.

        :param tabs: Список вкладок (основных или вложенных).
        :return: JSON-структура с данными вкладок.
        """
        async def process_single_tab(tab):
            tab_data = {
                "title": tab.get('tabProperties', {}).get('title', 'Untitled Tab'),
                "tab_id": tab.get('tabProperties', {}).get('tabId', 'Unknown'),
                "index": tab.get('tabProperties', {}).get('index', 'No Index'),
                "tab_text": await self.extract_tab_content(tab),
                "children": []
            }

            # Обработка вложенных вкладок
            if 'childTabs' in tab:
                tab_data["children"] = await self.process_tabs(tab.get('childTabs', []))

            return tab_data

        return await asyncio.gather(*(process_single_tab(tab) for tab in tabs))

    async def process_document(self, document_id):
        """
        Асинхронная обработка одного документа и сохранение результата.

        :param document_id: ID документа Google Docs.
        :return: JSON-структура обработанного документа или информация об ошибке.
        """
        try:
            self.logger.info("Начата обработка документа %s", document_id)
            document = await asyncio.to_thread(self.fetch_document_sync, document_id)

            if 'tabs' in document:
                tabs_json = await self.process_tabs(document['tabs'])
                return {
                    "document_id": document_id,
                    "title": document.get("title", "Unknown title"),
                    "tabs": tabs_json,
                    "status": {
                        "error_code": 0,  # Ошибок нет
                        "error_message": None
                    }
                }
            else:
                self.logger.warning("Документ %s не содержит вкладок", document_id)
                return {
                    "document_id": document_id,
                    "title": "Unknown title",
                    "tabs": [],
                    "status": {
                        "error_code": 1,
                        "error_message": "Документ не содержит вкладок"
                    }
                }
        except Exception as e:
            self.logger.error("Ошибка при обработке документа %s: %s", document_id, str(e))
            return {
                "document_id": document_id,
                "title": "Unknown title",
                "tabs": [],
                "status": {
                    "error_code": 2,
                    "error_message": traceback.format_exc()
                }
            }

    async def process_documents(self, document_ids):
        """
        Асинхронная обработка нескольких документов с ограничением на количество задач.

        :param document_ids: Список ID документов Google Docs.
        :return: Список загруженных документов (с данными или ошибками).
        """
        semaphore = asyncio.Semaphore(self.max_concurrent_tasks)

        async def process_with_semaphore(doc_id):
            async with semaphore:
                try:
                    return await self.process_document(doc_id)
                except Exception as e:
                    self.logger.error("Ошибка при обработке документа %s: %s", doc_id, str(e))
                    return {
                        "document_id": doc_id,
                        "title": "Unknown title",
                        "tabs": [],
                        "status": {
                            "error_code": 3,
                            "error_message": traceback.format_exc()
                        }
                    }

        self.logger.info("Начата обработка %d документов", len(document_ids))
        tasks = [process_with_semaphore(doc_id) for doc_id in document_ids]
        results = await asyncio.gather(*tasks, return_exceptions=True)

        self.logger.info("Обработка всех документов завершена")

        return results
