"""
BIBIVIDI — Recipe chain integration tests (TODO-23)

Tests the three BIBIVIDI-authored BSS 1.1 chain packs end-to-end using the
run_chain runner. Each test loads dep skills from scripts/ and runs the full
sequential pipeline on realistic sample input.
"""
from __future__ import annotations

import json
from pathlib import Path

import pytest

from bvd.engine.library import Script
from bvd.engine.runner import run_chain

SCRIPTS_DIR = Path(__file__).parent.parent / "scripts"


def _load_script(skill_id: str) -> Script:
    """Load a skill pack from scripts/ as a Script object."""
    skill_dir = SCRIPTS_DIR / skill_id
    meta = json.loads((skill_dir / "skill.json").read_text())
    code = (skill_dir / "skill.py").read_text()
    return Script(
        id=meta["id"],
        name=meta["name"],
        description=meta["description"],
        code=code,
        status="active",
        chain_ids=meta.get("chain", []),
        inputs_type=meta.get("inputs_type"),
        outputs_type=meta.get("outputs_type"),
        marketplace_price_eur=meta.get("marketplace_price_eur"),
    )


# ── Fixtures ──────────────────────────────────────────────────────────────────

SAMPLE_INVOICE = """\
Please process the following invoice for our accounting system.

INVOICE #INV-2026-0042
Vendor: Acme Supplies Ltd
Date: 2026-03-01
Due: 2026-03-31

Line Items:
  1. Cloud storage (annual)    $1,200.00
  2. Support tier (premium)    $500.00
  3. Setup fee                 $250.00
  4. Training session (2hr)    $300.00

Subtotal:  $2,250.00
VAT (20%): $450.00
TOTAL:     $2,700.00
"""

SAMPLE_DIFF = """\
Review this pull request diff for our backend service.

diff --git a/bvd/engine/matcher.py b/bvd/engine/matcher.py
--- a/bvd/engine/matcher.py
+++ b/bvd/engine/matcher.py
@@ -10,6 +10,20 @@ class Matcher:
+    async def assemble_pipeline(self, prompt: str):
+        input_type = _detect_input_type(prompt)
+        if input_type == "plain_text":
+            return None
+        graph = library.build_type_graph(await library.all())
+        path = _bfs_type_path(graph, input_type, "plain_text")
+        return AssemblyResult(pipeline=path, input_type=input_type, output_type="plain_text")
+
+def _detect_input_type(prompt: str) -> str:
+    head = prompt[:1000]
+    if "%PDF-" in head:
+        return "pdf"
+    return "plain_text"
"""

SAMPLE_DOCUMENT = """\
Analyse this document.

QUARTERLY REPORT — Q1 2026
Executive Summary

Revenue increased 18% year-over-year driven by strong enterprise adoption.
Key findings:
  - ARR grew from €2.1M to €2.5M
  - Churn rate reduced to 3.2%
  - NPS score improved to 62

Recommendations:
  1. Expand enterprise sales team by 3 FTEs
  2. Launch self-serve tier in Q2
  3. Invest in customer success automation

Methodology: cohort analysis across 240 active accounts, Jan–Mar 2026.
Conclusion: growth trajectory is sustainable; mid-market segment is the key lever.
"""


# ── Financial Pipeline ────────────────────────────────────────────────────────

@pytest.mark.asyncio
async def test_financial_pipeline_runs(monkeypatch):
    from bvd import config
    monkeypatch.setattr(config.settings, "enable_chains", True)

    chain = _load_script("financial-pipeline")
    dep_ids = chain.chain_ids
    deps = [_load_script(d) for d in dep_ids]

    result = await run_chain(chain, SAMPLE_INVOICE, deps)
    assert result.exit_code == 0
    assert not result.timed_out


@pytest.mark.asyncio
async def test_financial_pipeline_extracts_invoice_number(monkeypatch):
    from bvd import config
    monkeypatch.setattr(config.settings, "enable_chains", True)

    chain = _load_script("financial-pipeline")
    deps = [_load_script(d) for d in chain.chain_ids]

    result = await run_chain(chain, SAMPLE_INVOICE, deps)
    out = result.output.lower()
    assert "inv-2026-0042" in out or "2700" in out or "invoice" in out


@pytest.mark.asyncio
async def test_financial_pipeline_reduces_tokens(monkeypatch):
    from bvd import config
    monkeypatch.setattr(config.settings, "enable_chains", True)

    chain = _load_script("financial-pipeline")
    deps = [_load_script(d) for d in chain.chain_ids]

    result = await run_chain(chain, SAMPLE_INVOICE, deps)
    # Chain output must be shorter than the original
    assert len(result.output) < len(SAMPLE_INVOICE)


@pytest.mark.asyncio
async def test_financial_pipeline_has_bibividi_header(monkeypatch):
    from bvd import config
    monkeypatch.setattr(config.settings, "enable_chains", True)

    chain = _load_script("financial-pipeline")
    deps = [_load_script(d) for d in chain.chain_ids]

    result = await run_chain(chain, SAMPLE_INVOICE, deps)
    assert "[BIBIVIDI: invoice pre-processed]" in result.output


@pytest.mark.asyncio
async def test_financial_pipeline_is_paid():
    chain = _load_script("financial-pipeline")
    assert chain.marketplace_price_eur == pytest.approx(0.008)
    assert chain.is_paid


# ── Code Review Pipeline ──────────────────────────────────────────────────────

@pytest.mark.asyncio
async def test_code_review_pipeline_runs(monkeypatch):
    from bvd import config
    monkeypatch.setattr(config.settings, "enable_chains", True)

    chain = _load_script("code-review-pipeline")
    deps = [_load_script(d) for d in chain.chain_ids]

    result = await run_chain(chain, SAMPLE_DIFF, deps)
    assert result.exit_code == 0
    assert not result.timed_out


@pytest.mark.asyncio
async def test_code_review_pipeline_has_bibividi_header(monkeypatch):
    from bvd import config
    monkeypatch.setattr(config.settings, "enable_chains", True)

    chain = _load_script("code-review-pipeline")
    deps = [_load_script(d) for d in chain.chain_ids]

    result = await run_chain(chain, SAMPLE_DIFF, deps)
    assert "[BIBIVIDI: diff pre-processed]" in result.output


@pytest.mark.asyncio
async def test_code_review_pipeline_no_raw_delimiters(monkeypatch):
    from bvd import config
    monkeypatch.setattr(config.settings, "enable_chains", True)

    chain = _load_script("code-review-pipeline")
    deps = [_load_script(d) for d in chain.chain_ids]

    result = await run_chain(chain, SAMPLE_DIFF, deps)
    # Finalizer strips the === wrappers
    assert "=== CODE REVIEW BRIEF ===" not in result.output
    assert "=== END REVIEW ===" not in result.output


@pytest.mark.asyncio
async def test_code_review_pipeline_reduces_tokens(monkeypatch):
    from bvd import config
    monkeypatch.setattr(config.settings, "enable_chains", True)

    chain = _load_script("code-review-pipeline")
    deps = [_load_script(d) for d in chain.chain_ids]

    result = await run_chain(chain, SAMPLE_DIFF, deps)
    assert len(result.output) < len(SAMPLE_DIFF)


@pytest.mark.asyncio
async def test_code_review_pipeline_is_paid():
    chain = _load_script("code-review-pipeline")
    assert chain.marketplace_price_eur == pytest.approx(0.006)
    assert chain.is_paid


# ── Document Intelligence Suite ───────────────────────────────────────────────

@pytest.mark.asyncio
async def test_document_intelligence_suite_runs(monkeypatch):
    from bvd import config
    monkeypatch.setattr(config.settings, "enable_chains", True)

    chain = _load_script("document-intelligence-suite")
    deps = [_load_script(d) for d in chain.chain_ids]

    result = await run_chain(chain, SAMPLE_DOCUMENT, deps)
    assert result.exit_code == 0
    assert not result.timed_out


@pytest.mark.asyncio
async def test_document_intelligence_suite_has_bibividi_header(monkeypatch):
    from bvd import config
    monkeypatch.setattr(config.settings, "enable_chains", True)

    chain = _load_script("document-intelligence-suite")
    deps = [_load_script(d) for d in chain.chain_ids]

    result = await run_chain(chain, SAMPLE_DOCUMENT, deps)
    assert "[BIBIVIDI: document pre-processed]" in result.output


@pytest.mark.asyncio
async def test_document_intelligence_suite_reduces_tokens(monkeypatch):
    from bvd import config
    monkeypatch.setattr(config.settings, "enable_chains", True)

    chain = _load_script("document-intelligence-suite")
    deps = [_load_script(d) for d in chain.chain_ids]

    result = await run_chain(chain, SAMPLE_DOCUMENT, deps)
    assert len(result.output) < len(SAMPLE_DOCUMENT)


@pytest.mark.asyncio
async def test_document_intelligence_suite_is_paid():
    chain = _load_script("document-intelligence-suite")
    assert chain.marketplace_price_eur == pytest.approx(0.005)
    assert chain.is_paid


# ── Chain metadata ────────────────────────────────────────────────────────────

def test_all_chains_have_correct_dep_ids():
    for chain_id, expected_deps in [
        ("financial-pipeline", ["invoice-parser", "line-validator", "totals-summarizer"]),
        ("code-review-pipeline", ["diff-parser", "complexity-scorer", "review-formatter"]),
        (
            "document-intelligence-suite",
            ["pdf-text-extractor", "type-classifier", "content-router"],
        ),
    ]:
        chain = _load_script(chain_id)
        assert chain.chain_ids == expected_deps, f"{chain_id}: wrong deps"


def test_all_chains_have_skill_py():
    for chain_id in ("financial-pipeline", "code-review-pipeline", "document-intelligence-suite"):
        skill_py = SCRIPTS_DIR / chain_id / "skill.py"
        assert skill_py.exists() and skill_py.stat().st_size > 10, (
            f"{chain_id}/skill.py is missing or empty"
        )
