"""
File-to-text conversion service for NOMAZRA.
Converts images, audio, PDFs, DOCX, TXT to plain text so that
GPT can process them without burning tokens on multimodal input.

All processing happens server-side. Files are NEVER sent to OpenAI directly.
"""
import os
import io
import re
import logging
import tempfile
import subprocess

logger = logging.getLogger(__name__)


def extract_text(file_path, mime_type):
    """
    Dispatch to the correct extractor based on MIME type.
    Returns extracted text string.
    """
    mime = (mime_type or '').lower()

    if mime == 'application/pdf':
        return _extract_pdf(file_path)
    elif mime in (
        'application/msword',
        'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    ):
        return _extract_docx(file_path)
    elif mime == 'text/plain' or mime == 'text/csv':
        return _extract_text_file(file_path)
    elif mime.startswith('image/'):
        return _extract_image_ocr(file_path)
    elif mime.startswith('audio/'):
        return _extract_audio_whisper(file_path)
    else:
        return f"[Unsupported file type: {mime}]"


def _extract_pdf(file_path):
    """Extract text from PDF using pdfplumber (no external service)."""
    try:
        import pdfplumber
        text_parts = []
        with pdfplumber.open(file_path) as pdf:
            for page in pdf.pages[:50]:  # Cap at 50 pages
                page_text = page.extract_text()
                if page_text:
                    text_parts.append(page_text)
        result = '\n\n'.join(text_parts)
        if not result.strip():
            # PDF might be scanned — fallback to OCR
            return _ocr_pdf_fallback(file_path)
        return result[:50000]  # Cap at 50k chars
    except Exception as e:
        logger.error("PDF extraction failed: %s", e)
        return f"[PDF extraction error: {e}]"


def _ocr_pdf_fallback(file_path):
    """For scanned PDFs — convert pages to images then OCR."""
    try:
        from pdf2image import convert_from_path
        images = convert_from_path(file_path, dpi=150, first_page=1, last_page=10)
        text_parts = []
        for img in images:
            text = _ocr_pil_image(img)
            if text.strip():
                text_parts.append(text)
        return '\n\n'.join(text_parts)[:50000]
    except ImportError:
        return "[Scanned PDF — install pdf2image + poppler for OCR]"
    except Exception as e:
        logger.error("PDF OCR fallback failed: %s", e)
        return f"[PDF OCR error: {e}]"


def _extract_docx(file_path):
    """Extract text from DOCX files."""
    try:
        from docx import Document
        doc = Document(file_path)
        paragraphs = [p.text for p in doc.paragraphs if p.text.strip()]
        return '\n\n'.join(paragraphs)[:50000]
    except Exception as e:
        logger.error("DOCX extraction failed: %s", e)
        return f"[DOCX extraction error: {e}]"


def _extract_text_file(file_path):
    """Read plain text files."""
    try:
        with open(file_path, 'r', encoding='utf-8', errors='replace') as f:
            return f.read()[:50000]
    except Exception as e:
        logger.error("Text file read failed: %s", e)
        return f"[Text read error: {e}]"


def _extract_image_ocr(file_path):
    """OCR an image using Tesseract."""
    try:
        from PIL import Image
        img = Image.open(file_path)
        return _ocr_pil_image(img)
    except Exception as e:
        logger.error("Image OCR failed: %s", e)
        return f"[Image OCR error: {e}]"


def _ocr_pil_image(pil_image):
    """Run Tesseract OCR on a PIL Image object."""
    try:
        import pytesseract
        text = pytesseract.image_to_string(pil_image, lang='eng')
        return text.strip()[:30000]
    except ImportError:
        return "[Install pytesseract + tesseract-ocr for image text extraction]"
    except Exception as e:
        logger.error("Tesseract OCR failed: %s", e)
        return f"[OCR error: {e}]"


def _extract_audio_whisper(file_path):
    """
    Transcribe audio using OpenAI Whisper API (whisper-1).
    Cheapest: $0.006/minute. Much cheaper than sending audio to GPT-4.
    """
    try:
        import openai
        client = openai.OpenAI(api_key=os.getenv('OPENAI_API_KEY'))

        # Whisper has a 25MB limit. If larger, we need to chunk.
        file_size = os.path.getsize(file_path)
        if file_size > 25 * 1024 * 1024:
            return _transcribe_large_audio(file_path, client)

        with open(file_path, 'rb') as f:
            transcript = client.audio.transcriptions.create(
                model='whisper-1',
                file=f,
                response_format='text',
            )
        return transcript.strip()[:50000]
    except Exception as e:
        logger.error("Audio transcription failed: %s", e)
        return f"[Audio transcription error: {e}]"


def _transcribe_large_audio(file_path, client):
    """Split large audio into chunks and transcribe each."""
    try:
        # Use ffmpeg to split into 10-minute chunks
        with tempfile.TemporaryDirectory() as tmpdir:
            chunk_pattern = os.path.join(tmpdir, 'chunk_%03d.mp3')
            subprocess.run(
                [
                    'ffmpeg', '-i', file_path,
                    '-f', 'segment', '-segment_time', '600',
                    '-c:a', 'libmp3lame', '-q:a', '4',
                    chunk_pattern,
                ],
                capture_output=True, timeout=120,
                check=True,
            )

            chunks = sorted(
                f for f in os.listdir(tmpdir) if f.startswith('chunk_')
            )
            texts = []
            for chunk_name in chunks[:6]:  # Max 6 chunks = 60 min
                chunk_path = os.path.join(tmpdir, chunk_name)
                with open(chunk_path, 'rb') as f:
                    t = client.audio.transcriptions.create(
                        model='whisper-1', file=f, response_format='text',
                    )
                    texts.append(t.strip())

            return '\n\n'.join(texts)[:50000]
    except Exception as e:
        logger.error("Large audio transcription failed: %s", e)
        return f"[Large audio transcription error: {e}]"


def sanitize_extracted_text(text):
    """Clean up extracted text — remove control chars, excessive whitespace."""
    if not text:
        return ''
    # Remove control characters except newlines/tabs
    text = re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', '', text)
    # Collapse excessive newlines
    text = re.sub(r'\n{4,}', '\n\n\n', text)
    # Collapse excessive spaces
    text = re.sub(r' {3,}', '  ', text)
    return text.strip()
