"""
Test the complete chunk preview → apply → embed workflow.
"""

import tempfile
from pathlib import Path

import pytest

from justembed.chunker import chunk_text
from justembed.embedder import E5Embedder
from justembed import db
from justembed.config import ensure_workspace_structure


SAMPLE_TEXT = """
This is a test document with multiple paragraphs.

The second paragraph contains more information about the topic.

The third paragraph wraps up the discussion.
""".strip()


def test_chunk_preview_workflow():
    """Test the preview → apply → embed workflow."""
    with tempfile.TemporaryDirectory() as tmpdir:
        workspace = Path(tmpdir)
        ensure_workspace_structure(workspace)
        
        # Create KB
        db.create_kb(workspace, "test_kb")
        
        # Step 1: Preview chunks
        chunks = chunk_text(SAMPLE_TEXT, file="test.txt", max_tokens=50)
        assert len(chunks) >= 1
        
        # Step 2: Apply chunking (save without embeddings)
        conn = db.get_connection(workspace, "test_kb")
        db.insert_chunks_without_embeddings(conn, "test.txt", chunks)
        
        # Verify chunks saved without embeddings
        saved_chunks = db.get_chunks_without_embeddings(conn, "test.txt")
        assert len(saved_chunks) == len(chunks)
        for chunk in saved_chunks:
            assert "id" in chunk
            assert "text" in chunk
        
        # Step 3: Embed chunks
        emb = E5Embedder()
        embeddings = emb.embed([c["text"] for c in saved_chunks])
        assert len(embeddings) == len(saved_chunks)
        
        # Step 4: Update with embeddings
        db.update_embeddings(conn, saved_chunks, embeddings)
        
        # Verify embeddings saved
        remaining = db.get_chunks_without_embeddings(conn, "test.txt")
        assert len(remaining) == 0
        
        # Verify we can query
        q_emb = emb.embed_query("test document")
        results = db.query_chunks(conn, q_emb, top_k=3, kb_name="test_kb")
        assert len(results) >= 1
        
        conn.close()


def test_insert_chunks_without_embeddings():
    """Test inserting chunks without embeddings."""
    with tempfile.TemporaryDirectory() as tmpdir:
        workspace = Path(tmpdir)
        ensure_workspace_structure(workspace)
        
        db.create_kb(workspace, "test_kb")
        conn = db.get_connection(workspace, "test_kb")
        
        chunks = [
            {"file": "test.txt", "chunk_index": 0, "text": "First chunk"},
            {"file": "test.txt", "chunk_index": 1, "text": "Second chunk"},
        ]
        
        db.insert_chunks_without_embeddings(conn, "test.txt", chunks)
        
        # Verify chunks exist without embeddings
        saved = db.get_chunks_without_embeddings(conn, "test.txt")
        assert len(saved) == 2
        assert saved[0]["text"] == "First chunk"
        assert saved[1]["text"] == "Second chunk"
        
        conn.close()


def test_update_embeddings():
    """Test updating chunks with embeddings."""
    with tempfile.TemporaryDirectory() as tmpdir:
        workspace = Path(tmpdir)
        ensure_workspace_structure(workspace)
        
        db.create_kb(workspace, "test_kb")
        conn = db.get_connection(workspace, "test_kb")
        
        chunks = [
            {"file": "test.txt", "chunk_index": 0, "text": "Test chunk"},
        ]
        
        db.insert_chunks_without_embeddings(conn, "test.txt", chunks)
        saved = db.get_chunks_without_embeddings(conn, "test.txt")
        
        # Create fake embeddings
        embeddings = [[0.1] * 384]
        
        db.update_embeddings(conn, saved, embeddings)
        
        # Verify no chunks without embeddings
        remaining = db.get_chunks_without_embeddings(conn, "test.txt")
        assert len(remaining) == 0
        
        conn.close()


def test_chunking_options():
    """Test different chunking options."""
    text = """# Heading 1

Paragraph 1 content with more words to make it longer.

## Heading 2

Paragraph 2 content with additional text to ensure different chunking.
"""
    
    # Test with headings split
    chunks_with_headings = chunk_text(
        text, 
        file="test.txt",
        split_by_headings=True,
        split_by_paragraphs=True,
        max_tokens=20,  # Small limit to force splitting
    )
    
    # Test without headings split
    chunks_without_headings = chunk_text(
        text,
        file="test.txt", 
        split_by_headings=False,
        split_by_paragraphs=True,
        max_tokens=20,  # Same limit
    )
    
    # With headings split, should have more chunks
    # (headings become separate blocks)
    assert len(chunks_with_headings) >= len(chunks_without_headings)


def test_kb_name_validation():
    """Test KB name validation."""
    with tempfile.TemporaryDirectory() as tmpdir:
        workspace = Path(tmpdir)
        ensure_workspace_structure(workspace)
        
        # Valid names
        db.create_kb(workspace, "valid_kb_123")
        assert "valid_kb_123" in db.list_kbs(workspace)
        
        # Invalid names should raise ValueError
        with pytest.raises(ValueError):
            db.create_kb(workspace, "invalid-name")  # hyphen not allowed
        
        with pytest.raises(ValueError):
            db.create_kb(workspace, "invalid name")  # space not allowed
        
        with pytest.raises(ValueError):
            db.create_kb(workspace, "a" * 65)  # too long


def test_upload_history():
    """Test upload history tracking."""
    with tempfile.TemporaryDirectory() as tmpdir:
        workspace = Path(tmpdir)
        ensure_workspace_structure(workspace)
        
        # Add files to history
        for i in range(55):
            db.add_upload_history(workspace, f"file_{i}.txt")
        
        # Verify history DB was created
        history_path = workspace / "kb" / "_history.duckdb"
        assert history_path.exists()
        
        # Verify purge happened (should have 50 entries + 1 purge message = 51)
        import duckdb
        conn = duckdb.connect(str(history_path))
        count = conn.execute("SELECT COUNT(*) FROM upload_history").fetchone()[0]
        conn.close()
        
        # Should have 51 entries (50 files + 1 purge message)
        assert count == 51


def test_multiple_files_same_kb():
    """Test uploading multiple files to same KB."""
    with tempfile.TemporaryDirectory() as tmpdir:
        workspace = Path(tmpdir)
        ensure_workspace_structure(workspace)
        
        db.create_kb(workspace, "multi_file_kb")
        conn = db.get_connection(workspace, "multi_file_kb")
        
        # Add chunks from file 1
        chunks1 = chunk_text("File 1 content", file="file1.txt")
        db.insert_chunks_without_embeddings(conn, "file1.txt", chunks1)
        
        # Add chunks from file 2
        chunks2 = chunk_text("File 2 content", file="file2.txt")
        db.insert_chunks_without_embeddings(conn, "file2.txt", chunks2)
        
        # Verify both files exist
        saved1 = db.get_chunks_without_embeddings(conn, "file1.txt")
        saved2 = db.get_chunks_without_embeddings(conn, "file2.txt")
        
        assert len(saved1) >= 1
        assert len(saved2) >= 1
        
        conn.close()


def test_delete_kb():
    """Test deleting a knowledge base."""
    with tempfile.TemporaryDirectory() as tmpdir:
        workspace = Path(tmpdir)
        ensure_workspace_structure(workspace)
        
        # Create KB
        db.create_kb(workspace, "test_delete_kb")
        assert "test_delete_kb" in db.list_kbs(workspace)
        
        # Delete KB
        db.delete_kb(workspace, "test_delete_kb")
        assert "test_delete_kb" not in db.list_kbs(workspace)
        
        # Verify file is gone
        kb_path = workspace / "kb" / "test_delete_kb.duckdb"
        assert not kb_path.exists()


def test_history_not_in_kb_list():
    """Test that _history is not listed as a KB."""
    with tempfile.TemporaryDirectory() as tmpdir:
        workspace = Path(tmpdir)
        ensure_workspace_structure(workspace)
        
        # Add some upload history (creates _history.duckdb)
        db.add_upload_history(workspace, "test.txt")
        
        # Verify _history.duckdb exists
        history_path = workspace / "kb" / "_history.duckdb"
        assert history_path.exists()
        
        # Verify _history is NOT in KB list
        kbs = db.list_kbs(workspace)
        assert "_history" not in kbs
