from __future__ import annotations

import json
import tempfile
import unittest
from io import BytesIO
from pathlib import Path

from reportlab.pdfgen import canvas

from us_cpa.cases import CaseManager
from us_cpa.prepare import PrepareEngine
from us_cpa.review import ReviewEngine, render_review_memo, render_review_summary
from us_cpa.sources import TaxYearCorpus, bootstrap_irs_catalog


class ReviewEngineTests(unittest.TestCase):
    def build_prepared_case(self, temp_dir: str) -> tuple[Path, TaxYearCorpus]:
        case_dir = Path(temp_dir) / "2025-jane-doe"
        manager = CaseManager(case_dir)
        manager.create_case(case_label="Jane Doe", tax_year=2025)
        manager.intake(
            tax_year=2025,
            user_facts={
                "taxpayer.fullName": "Jane Doe",
                "filingStatus": "single",
                "wages": 50000,
                "taxableInterest": 100,
                "federalWithholding": 6000,
            },
            document_paths=[],
        )
        corpus = TaxYearCorpus(cache_root=Path(temp_dir) / "cache")

        def fake_fetch(url: str) -> bytes:
            buffer = BytesIO()
            pdf = canvas.Canvas(buffer)
            pdf.drawString(72, 720, f"Template for {url}")
            pdf.save()
            return buffer.getvalue()

        corpus.download_catalog(2025, bootstrap_irs_catalog(2025), fetcher=fake_fetch)
        PrepareEngine(corpus=corpus).prepare_case(case_dir)
        return case_dir, corpus

    def test_review_detects_mismatched_return_and_missing_artifacts(self) -> None:
        with tempfile.TemporaryDirectory() as temp_dir:
            case_dir, corpus = self.build_prepared_case(temp_dir)
            normalized_path = case_dir / "return" / "normalized-return.json"
            normalized = json.loads(normalized_path.read_text())
            normalized["totals"]["adjustedGrossIncome"] = 99999.0
            normalized_path.write_text(json.dumps(normalized, indent=2))

            artifacts_path = case_dir / "output" / "artifacts.json"
            artifacts = json.loads(artifacts_path.read_text())
            artifacts["artifacts"] = []
            artifacts["artifactCount"] = 0
            artifacts_path.write_text(json.dumps(artifacts, indent=2))

            review = ReviewEngine(corpus=corpus).review_case(case_dir)

            self.assertEqual(review["status"], "reviewed")
            self.assertEqual(review["findings"][0]["severity"], "high")
            self.assertIn("adjusted gross income", review["findings"][0]["title"].lower())
            self.assertTrue(any("missing rendered artifact" in item["title"].lower() for item in review["findings"]))

    def test_review_detects_reporting_omissions_from_source_facts(self) -> None:
        with tempfile.TemporaryDirectory() as temp_dir:
            case_dir, corpus = self.build_prepared_case(temp_dir)
            normalized_path = case_dir / "return" / "normalized-return.json"
            normalized = json.loads(normalized_path.read_text())
            normalized["income"]["taxableInterest"] = 0.0
            normalized["totals"]["adjustedGrossIncome"] = 50000.0
            normalized_path.write_text(json.dumps(normalized, indent=2))

            facts_path = case_dir / "extracted" / "facts.json"
            facts_payload = json.loads(facts_path.read_text())
            facts_payload["facts"]["taxableInterest"] = {
                "value": 1750.0,
                "sources": [{"sourceType": "document_extract", "sourceName": "1099-int.txt"}],
            }
            facts_path.write_text(json.dumps(facts_payload, indent=2))

            review = ReviewEngine(corpus=corpus).review_case(case_dir)

            self.assertTrue(
                any("likely omitted taxable interest" in item["title"].lower() for item in review["findings"])
            )

    def test_review_flags_high_complexity_positions_for_specialist_follow_up(self) -> None:
        with tempfile.TemporaryDirectory() as temp_dir:
            case_dir, corpus = self.build_prepared_case(temp_dir)
            normalized_path = case_dir / "return" / "normalized-return.json"
            normalized = json.loads(normalized_path.read_text())
            normalized["requiredForms"].append("f6251")
            normalized["taxes"]["alternativeMinimumTax"] = 300.0
            normalized_path.write_text(json.dumps(normalized, indent=2))

            review = ReviewEngine(corpus=corpus).review_case(case_dir)

            self.assertTrue(
                any("high-complexity tax position" in item["title"].lower() for item in review["findings"])
            )

    def test_review_renderers_produce_summary_and_memo(self) -> None:
        review = {
            "status": "reviewed",
            "findings": [
                {
                    "severity": "high",
                    "title": "Adjusted gross income mismatch",
                    "explanation": "Stored AGI does not match recomputed AGI.",
                    "suggestedAction": "Update Form 1040 line 11.",
                    "authorities": [{"title": "Instructions for Form 1040 and Schedules 1-3"}],
                }
            ],
        }

        summary = render_review_summary(review)
        memo = render_review_memo(review)

        self.assertIn("Adjusted gross income mismatch", summary)
        self.assertIn("# Review Memo", memo)
        self.assertIn("Suggested correction", memo)


if __name__ == "__main__":
    unittest.main()
