"""Report generation end-to-end against a real (SQLite) DB: real SourceDocument/DetectedChange rows in, a persisted Report (JSON + Markdown) out, via the mock LLM provider.""" from __future__ import annotations import uuid from datetime import UTC, datetime import pytest from sqlalchemy import select from sqlalchemy.orm import selectinload from app.analysis.llm.mock import MockLLMProvider from app.models.company import Company from app.models.detected_change import DetectedChange from app.models.enums import ChangeType, MonitoringRunTrigger, ReportType, SeverityLevel, SourceType from app.models.monitoring_run import MonitoringRun from app.models.report import Report from app.models.snapshot import Snapshot from app.models.source import Source from app.models.source_document import SourceDocument from app.repositories.company_repository import CompanyRepository from app.services.report_service import generate_and_persist_report async def _make_company_with_evidence(db_session) -> Company: company = Company( id=uuid.uuid4(), user_id=uuid.uuid4(), name="Acme Mobility Systems", slug=f"acme-mobility-{uuid.uuid4().hex[:6]}", monitoring_focus="EV manufacturing expansion and battery technology", ) db_session.add(company) await db_session.flush() source = Source( company_id=company.id, source_type=SourceType.JOB_POSTING, name="Careers", base_url="https://acme.example/careers", ) db_session.add(source) await db_session.flush() db_session.add( SourceDocument( source_id=source.id, company_id=company.id, url="https://acme.example/careers/battery-engineer", canonical_url="https://acme.example/careers/battery-engineer", title="Senior Battery Engineer", author=None, publication_date=None, retrieved_date=datetime.now(UTC), content_text="We are hiring a senior battery engineer to lead our new EV platform.", content_hash="hash1", metadata_json={}, extraction_method="job_link_heuristic", trust_score=0.7, ) ) run = MonitoringRun(company_id=company.id, trigger_type=MonitoringRunTrigger.MANUAL) db_session.add(run) await db_session.flush() snapshot = Snapshot( company_id=company.id, source_id=source.id, snapshot_type=source.source_type.value, hash="hash1", structured_summary={"urls": ["/careers/battery-engineer"]}, text_summary="Senior Battery Engineer", monitoring_run_id=run.id, ) db_session.add(snapshot) await db_session.flush() db_session.add( DetectedChange( company_id=company.id, source_id=source.id, monitoring_run_id=run.id, current_snapshot_id=snapshot.id, change_type=ChangeType.NEW_DOCUMENT, raw_diff={"structured_added": ["/careers/battery-engineer"], "structured_removed": []}, significance_score=0.6, confidence_score=0.75, severity=SeverityLevel.HIGH, summary="1 new item detected", ) ) await db_session.commit() return await CompanyRepository(db_session).get_for_user(company.id, company.user_id) @pytest.mark.asyncio async def test_generate_report_persists_structured_and_markdown(db_session, settings): company = await _make_company_with_evidence(db_session) llm = MockLLMProvider() report = await generate_and_persist_report( db_session, settings, llm, company, report_type=ReportType.BASELINE ) assert report.id is not None assert report.report_type == ReportType.BASELINE assert report.model_provider == "mock" assert "Acme Mobility Systems" in report.executive_summary assert report.structured_report["executive_summary"] == report.executive_summary assert len(report.structured_report["recent_developments"]) == 1 assert len(report.structured_report["hiring_signals"]) == 1 assert "# Competitive Intelligence Report: Acme Mobility Systems" in report.markdown_content assert "## 15. Sources" in report.markdown_content assert "battery-engineer" in report.markdown_content persisted = ( await db_session.execute(select(Report).where(Report.id == report.id)) ).scalar_one() assert persisted.company_id == company.id @pytest.mark.asyncio async def test_generate_report_with_no_evidence_is_still_honest(db_session, settings): company = Company( id=uuid.uuid4(), user_id=uuid.uuid4(), name="Empty Co", slug=f"empty-co-{uuid.uuid4().hex[:6]}", ) db_session.add(company) await db_session.commit() result = await db_session.execute( select(Company) .where(Company.id == company.id) .options( selectinload(Company.aliases), selectinload(Company.competitors), selectinload(Company.enrichment), ) ) company = result.scalar_one() report = await generate_and_persist_report( db_session, settings, MockLLMProvider(), company, report_type=ReportType.BASELINE ) assert "0 collected document" in report.executive_summary assert report.structured_report["recent_developments"] == []