#!/usr/bin/env python3.11
import os
import re
import shutil
import sys
from datetime import datetime
from pathlib import Path
from concurrent.futures import ProcessPoolExecutor, as_completed
from pypdf import PdfReader
from langdetect import detect, DetectorFactory
from docx import Document
import ebooklib
from ebooklib import epub
from bs4 import BeautifulSoup
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont

DetectorFactory.seed = 0

BASE_DIR = Path("/home/dayhanbiz/public_html/3-damja.science")
INPUT_DIR = BASE_DIR / "depository" / "Необработанные поступления"
TARGET_DIR = BASE_DIR / "depository" / "recognized-language"
ERROR_LOG_FILE = BASE_DIR / "librarian" / "router_errors.log"
PROCESS_LOG_FILE = BASE_DIR / "librarian" / "router_process.log"

LANG_DIRS = {
    "ru": TARGET_DIR / "ru",
    "old-ru": TARGET_DIR / "old-ru",
    "en": TARGET_DIR / "en",
    "ar": TARGET_DIR / "ar",
    "per": TARGET_DIR / "per",
    "unknown": TARGET_DIR / "unknown"
}

# Динамический поиск кириллического шрифта в системе
CYRILLIC_FONT_NAME = "Helvetica"
POSSIBLE_FONT_PATHS = [
    "/usr/share/fonts/dejavu-sans-fonts/DejaVuSans.ttf",
    "/usr/share/fonts/dejavu/DejaVuSans.ttf",
    "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
    "/usr/share/fonts/liberation-sans/LiberationSans-Regular.ttf",
    "/usr/share/fonts/liberation/LiberationSans-Regular.ttf",
]

# Сначала проверяем стандартные пути, затем ищем динамически по всей папке /usr/share/fonts
found_font_path = None
for fp in POSSIBLE_FONT_PATHS:
    if os.path.exists(fp):
        found_font_path = fp
        break

if not found_font_path and os.path.exists("/usr/share/fonts"):
    for font_file in Path("/usr/share/fonts").rglob("*.ttf"):
        if "dejavu" in font_file.name.lower() or "liberation" in font_file.name.lower() or "free" in font_file.name.lower():
            found_font_path = str(font_file)
            break

if found_font_path:
    try:
        pdfmetrics.registerFont(TTFont("DejaVuCyrillic", found_font_path))
        CYRILLIC_FONT_NAME = "DejaVuCyrillic"
    except Exception:
        pass

def log_process_entry(message: str):
    """Запись всех операций и перемещений в router_process.log."""
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    with open(PROCESS_LOG_FILE, "a", encoding="utf-8") as pf:
        pf.write(f"[{timestamp}] {message}\n")

def log_error_entry(message: str):
    """Запись ошибки в отдельный журнал router_errors.log."""
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    with open(ERROR_LOG_FILE, "a", encoding="utf-8") as ef:
        ef.write(f"[{timestamp}] {message}\n")

def check_old_russian(text: str) -> bool:
    old_chars_pattern = r'[ѣѣѢіІѳѲѵѴ]'
    hard_sign_endings = r'\b[а-яА-Яa-zA-Z]+ъ\b'
    return bool(re.search(old_chars_pattern, text) or re.search(hard_sign_endings, text))

def convert_txt_to_pdf(txt_path: Path, output_pdf: Path):
    doc = SimpleDocTemplate(str(output_pdf), pagesize=letter)
    styles = getSampleStyleSheet()
    style = ParagraphStyle(
        'Normal', 
        parent=styles['Normal'], 
        fontName=CYRILLIC_FONT_NAME, 
        fontSize=10, 
        leading=12
    )
    story = []
    
    with open(txt_path, 'r', encoding='utf-8', errors='ignore') as f:
        for line in f:
            text = line.strip()
            if text:
                text = text.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')
                story.append(Paragraph(text, style))
                story.append(Spacer(1, 4))
    doc.build(story)

def convert_docx_to_pdf(docx_path: Path, output_pdf: Path):
    doc = SimpleDocTemplate(str(output_pdf), pagesize=letter)
    styles = getSampleStyleSheet()
    style = ParagraphStyle(
        'Normal', 
        parent=styles['Normal'], 
        fontName=CYRILLIC_FONT_NAME, 
        fontSize=10, 
        leading=12
    )
    story = []
    
    docx_doc = Document(docx_path)
    for p in docx_doc.paragraphs:
        text = p.text.strip()
        if text:
            text = text.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')
            story.append(Paragraph(text, style))
            story.append(Spacer(1, 4))
    doc.build(story)

def convert_epub_to_pdf(epub_path: Path, output_pdf: Path):
    book = epub.read_epub(str(epub_path))
    text_content = []
    
    for item in book.get_items():
        if item.get_type() == ebooklib.ITEM_DOCUMENT:
            soup = BeautifulSoup(item.get_content(), 'html.parser')
            text_content.append(soup.get_text())
            
    full_text = "\n".join(text_content)
    temp_txt = output_pdf.with_suffix('.tmp_epub.txt')
    with open(temp_txt, 'w', encoding='utf-8') as f:
        f.write(full_text)
        
    convert_txt_to_pdf(temp_txt, output_pdf)
    if temp_txt.exists():
        temp_txt.unlink()

def convert_fb2_to_pdf(fb2_path: Path, output_pdf: Path):
    """Парсинг XML-структуры FB2 файлов."""
    with open(fb2_path, 'rb') as f:
        content = f.read()
        
    soup = BeautifulSoup(content, 'xml')
    paragraphs = soup.find_all('p')
    
    text_content = [p.get_text().strip() for p in paragraphs if p.get_text().strip()]
    
    if not text_content:
        soup = BeautifulSoup(content, 'html.parser')
        text_content = [soup.get_text()]
        
    full_text = "\n".join(text_content)
    temp_txt = output_pdf.with_suffix('.tmp_fb2.txt')
    with open(temp_txt, 'w', encoding='utf-8') as f:
        f.write(full_text)
        
    convert_txt_to_pdf(temp_txt, output_pdf)
    if temp_txt.exists():
        temp_txt.unlink()

def ensure_pdf(file_path: Path) -> Path:
    if not file_path.exists():
        raise FileNotFoundError(f"Файл не найден: {file_path}")

    ext = file_path.suffix.lower()
    if ext == '.pdf':
        return file_path
        
    output_pdf = file_path.with_suffix('.pdf')
    
    if ext == '.txt':
        convert_txt_to_pdf(file_path, output_pdf)
    elif ext == '.docx':
        convert_docx_to_pdf(file_path, output_pdf)
    elif ext == '.epub':
        convert_epub_to_pdf(file_path, output_pdf)
    elif ext == '.fb2':
        convert_fb2_to_pdf(file_path, output_pdf)
    else:
        return file_path
        
    return output_pdf

def extract_pages_4_to_8(pdf_path: Path) -> str:
    try:
        reader = PdfReader(str(pdf_path))
        num_pages = len(reader.pages)
        extracted_text = ""
        
        start_page = min(3, max(0, num_pages - 1))
        end_page = min(8, num_pages)
        
        for page_num in range(start_page, end_page):
            text = reader.pages[page_num].extract_text() or ""
            extracted_text += "\n" + text
            
        return extracted_text.strip()
    except Exception:
        return ""

def detect_language(text: str) -> str:
    if not text or len(text.strip()) < 20:
        return "unknown"
        
    if check_old_russian(text):
        return "old-ru"
        
    try:
        lang = detect(text)
        if lang == "ru":
            return "ru"
        elif lang == "en":
            return "en"
        elif lang == "ar":
            return "ar"
        elif lang == "fa":
            return "per"
        else:
            return "unknown"
    except Exception:
        return "unknown"

def process_single_file(file_path: Path) -> str:
    try:
        if not file_path.exists():
            return f"[ERROR] {file_path.name}: Файл отсутствует или уже перемещен"
            
        pdf_path = ensure_pdf(file_path)
        
        if pdf_path.suffix.lower() == '.pdf':
            text = extract_pages_4_to_8(pdf_path)
            lang_code = detect_language(text)
        else:
            lang_code = "unknown"
            
        target_folder = LANG_DIRS.get(lang_code, LANG_DIRS["unknown"])
        destination = target_folder / pdf_path.name
        
        if destination.exists():
            stem = pdf_path.stem
            suffix = pdf_path.suffix
            counter = 1
            while destination.exists():
                destination = target_folder / f"{stem}_{counter}{suffix}"
                counter += 1
                
        shutil.move(str(pdf_path), str(destination))
        
        if file_path != pdf_path and file_path.exists():
            file_path.unlink()
            
        return f"[OK] {file_path.name} -> {lang_code}"
    except Exception as e:
        return f"[ERROR] {file_path.name}: {e}"

def main():
    for folder in LANG_DIRS.values():
        folder.mkdir(parents=True, exist_ok=True)
        
    files = [f for f in INPUT_DIR.glob('*') if f.is_file() and not f.name.startswith('.')]
    total_files = len(files)
    
    if not files:
        print("[LIBRARIAN] Нет файлов для обработки в папке Необработанные поступления.")
        return

    print(f"=== ЗАПУСК МНОГОПОТОЧНОГО ЯЗЫКОВОГО РОУТЕРА (12 ПОТОКОВ) ===")
    print(f"Шрифт: {CYRILLIC_FONT_NAME}")
    print(f"Файлов к обработке: {total_files}\n")

    completed = 0
    with ProcessPoolExecutor(max_workers=12) as executor:
        futures = {executor.submit(process_single_file, f): f for f in files}
        for future in as_completed(futures):
            completed += 1
            res = future.result()
            
            formatted_res = f"[{completed}/{total_files}] {res}"
            print(formatted_res, flush=True)
            
            if "[ERROR]" in res:
                log_error_entry(formatted_res)

    print("\n=== ВСЕ ФАЙЛЫ УСПЕШНО РАСПРЕДЕЛЕНЫ ПО ЯЗЫКОВЫМ ПАПКАМ ===")

if __name__ == "__main__":
    main()
