# Flyto2 Core - Source Available License
# Copyright (c) 2025 Flyto2. All Rights Reserved.
#
# This source code is licensed under the Flyto2 Source Available License v1.0.
# Commercial use requires a license. See LICENSE for details.

"""
PDF Parse Module
Extract text and metadata from PDF files
"""
import logging
import os
from typing import Any, Dict, List, Optional

from ...registry import register_module
from ...schema import compose, presets


logger = logging.getLogger(__name__)


@register_module(
    module_id='pdf.parse',
    version='1.0.0',
    category='document',
    subcategory='pdf',
    tags=['pdf', 'document', 'parse', 'extract', 'text', 'path_restricted'],
    label='Parse PDF',
    label_key='modules.pdf.parse.label',
    description='Extract text and metadata from PDF files',
    description_key='modules.pdf.parse.description',
    icon='FileText',
    color='#DC2626',

    # Connection types
    input_types=['file_path'],
    output_types=['text', 'object'],
    can_connect_to=['string.*', 'data.*', 'ai.*', 'flow.*'],
    can_receive_from=['file.*', 'data.*', 'http.*', 'flow.*', 'start'],

    # Execution settings
    timeout_ms=120000,
    retryable=False,
    concurrent_safe=True,

    # Security settings
    requires_credentials=False,
    handles_sensitive_data=True,
    required_permissions=['filesystem.read', 'filesystem.write'],

    params_schema=compose(
        presets.PDF_PATH(),
        presets.DOC_PAGES(),
        presets.DOC_EXTRACT_IMAGES(),
        presets.DOC_EXTRACT_TABLES(),
    ),
    output_schema={
        'text': {
            'type': 'string',
            'description': 'Extracted text content'
        ,
                'description_key': 'modules.pdf.parse.output.text.description'},
        'pages': {
            'type': 'array',
            'description': 'Text content per page'
        ,
                'description_key': 'modules.pdf.parse.output.pages.description',
            'placeholder': '1-5',
},
        'metadata': {
            'type': 'object',
            'description': 'PDF metadata (title, author, etc.)'
        ,
                'description_key': 'modules.pdf.parse.output.metadata.description'},
        'page_count': {
            'type': 'number',
            'description': 'Total number of pages'
        ,
                'description_key': 'modules.pdf.parse.output.page_count.description'}
    },
    examples=[
        {
            'title': 'Extract all text from PDF',
            'title_key': 'modules.pdf.parse.examples.basic.title',
            'params': {
                'path': '/tmp/document.pdf',
                'pages': 'all'
            }
        }
    ],
    author='Flyto Team',
    license='MIT'
)
async def pdf_parse(context: Dict[str, Any]) -> Dict[str, Any]:
    """Parse PDF and extract text"""
    try:
        import pypdf
    except ImportError:
        raise ImportError("pypdf is required for PDF parsing. Install with: pip install pypdf")

    params = context['params']
    path = params['path']
    pages_param = params.get('pages', 'all')
    extract_images = params.get('extract_images', False)
    extract_tables = params.get('extract_tables', False)

    # Validate file exists
    if not os.path.exists(path):
        raise FileNotFoundError(f"PDF file not found: {path}")

    # Open and parse PDF
    with open(path, 'rb') as f:
        reader = pypdf.PdfReader(f)
        total_pages = len(reader.pages)

        # Determine pages to extract
        page_indices = _parse_page_range(pages_param, total_pages)

        # Extract text from each page
        page_texts: List[str] = []
        for idx in page_indices:
            if 0 <= idx < total_pages:
                page = reader.pages[idx]
                text = page.extract_text() or ""
                page_texts.append(text)

        # Combine all text
        full_text = "\n\n".join(page_texts)

        # Extract metadata
        metadata = {}
        if reader.metadata:
            metadata = {
                'title': reader.metadata.get('/Title', ''),
                'author': reader.metadata.get('/Author', ''),
                'subject': reader.metadata.get('/Subject', ''),
                'creator': reader.metadata.get('/Creator', ''),
                'producer': reader.metadata.get('/Producer', ''),
                'creation_date': str(reader.metadata.get('/CreationDate', '')),
                'modification_date': str(reader.metadata.get('/ModDate', '')),
            }

    logger.info(f"Parsed PDF: {path} ({total_pages} pages)")

    result = {
        'ok': True,
        'text': full_text,
        'pages': page_texts,
        'metadata': metadata,
        'page_count': total_pages,
        'extracted_pages': len(page_texts)
    }

    return result


def _parse_page_range(pages: str, total: int) -> List[int]:
    """Parse page range string to list of indices (0-based)"""
    if pages.lower() == 'all':
        return list(range(total))

    indices = []
    parts = pages.replace(' ', '').split(',')

    for part in parts:
        if '-' in part:
            start, end = part.split('-')
            start_idx = int(start) - 1
            end_idx = int(end)
            indices.extend(range(start_idx, min(end_idx, total)))
        else:
            idx = int(part) - 1
            if 0 <= idx < total:
                indices.append(idx)

    return sorted(set(indices))
