import sys
import os
import queue
from unittest.mock import patch, MagicMock

# Ensure project root is on sys.path so imports of top-level modules work
PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
if PROJECT_ROOT not in sys.path:
    sys.path.insert(0, PROJECT_ROOT)

# Some heavy optional deps (like PyMuPDF `fitz`) may not be installed in test
# environment. Provide lightweight stubs to allow importing the orchestrator
# module for unit tests that patch out network/IO behavior.
import types
if 'fitz' not in sys.modules:
    sys.modules['fitz'] = types.ModuleType('fitz')

# Stub OpenAI and Google GenAI if not installed in this environment
if 'openai' not in sys.modules:
    openai_mod = types.ModuleType('openai')
    openai_mod.OpenAI = type('OpenAIStub', (), {})
    sys.modules['openai'] = openai_mod

if 'google' not in sys.modules:
    google_mod = types.ModuleType('google')
    genai_mod = types.ModuleType('google.genai')
    # minimal structure expected by orchestrator_ingest imports
    google_mod.genai = genai_mod
    sys.modules['google'] = google_mod
    sys.modules['google.genai'] = genai_mod

# Stub pymupdf4llm and rapidocr_onnxruntime used by core.parser.hybrid_parser
if 'pymupdf4llm' not in sys.modules:
    pymod = types.ModuleType('pymupdf4llm')
    def _to_md(pdf_path, **kwargs):
        return "# Dummy Extracted Title\n\nDummy extracted content."
    pymod.to_markdown = _to_md
    sys.modules['pymupdf4llm'] = pymod

if 'rapidocr_onnxruntime' not in sys.modules:
    ro_mod = types.ModuleType('rapidocr_onnxruntime')
    class RapidOCR:
        def __init__(self):
            pass
        def __call__(self, data):
            return ([], None)
    ro_mod.RapidOCR = RapidOCR
    sys.modules['rapidocr_onnxruntime'] = ro_mod

import app.services.ingestion as orch

print('Starting Task 4 repair tests...')

# Prepare a dummy worker starter that returns a queue and a thread-like object
def dummy_start_worker():
    q = queue.Queue()
    class DummyThread:
        def join(self, timeout=None):
            return
    return q, DummyThread()

# Test _repair_supabase_if_missing directly with patched dependencies
with patch('core.storage.supabase_client.check_supabase_hash', return_value=False) as p_check, \
     patch('core.storage.supabase_client.start_uploader_worker', side_effect=lambda: dummy_start_worker()) as p_start, \
     patch.object(orch.hybrid_parser, 'parse_pdf', return_value="# Sample Title\n\nSample content for testing.") as p_parse, \
     patch('core.parser.smart_chunker.generate_chunks', return_value=[{
         'file_hash': 'fakehash',
         'title': 'fake.pdf',
         'chunk_index': 0,
         'metadata_header': '## Sample',
         'content': 'chunk content'
     }]) as p_chunks:
    try:
        orch._repair_supabase_if_missing('fakehash', '/tmp/fake.pdf', 'fake.pdf')
        print('OK: _repair_supabase_if_missing executed without exception')
    except Exception as e:
        print('ERROR: _repair_supabase_if_missing raised exception:', e)

# Test process_sync_pdf early-exit path invokes repair (when node exists)
with patch('app.services.ingestion.check_node_exists', return_value=True) as p_node, \
     patch('app.services.ingestion._repair_supabase_if_missing') as p_repair:
    # Ensure a dummy file exists so get_md5_hash does not fail
    try:
        with open('/tmp/fake.pdf', 'wb') as fh:
            fh.write(b'%PDF-1.4\n%EOF')
    except Exception:
        pass

    res = orch.process_sync_pdf('/tmp/fake.pdf', driver=MagicMock(), or_client=MagicMock(), gemini_client=MagicMock())
    print('process_sync_pdf returned:', res)
    print('repair_called:', p_repair.called)

print('Task 4 repair tests finished.')
