from __future__ import annotations

import json
import os
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path


SKILL_DIR = Path(__file__).resolve().parents[1]
SRC_DIR = SKILL_DIR / "src"


def _pyproject_text() -> str:
    return (SKILL_DIR / "pyproject.toml").read_text()


class UsCpaCliSmokeTests(unittest.TestCase):
    def test_skill_scaffold_files_exist(self) -> None:
        self.assertTrue((SKILL_DIR / "SKILL.md").exists())
        self.assertTrue((SKILL_DIR / "pyproject.toml").exists())
        self.assertTrue((SKILL_DIR / "README.md").exists())
        self.assertTrue((SKILL_DIR / "scripts" / "us-cpa").exists())
        self.assertTrue(
            (SKILL_DIR.parent.parent / "docs" / "us-cpa.md").exists()
        )

    def test_pyproject_declares_runtime_and_dev_dependencies(self) -> None:
        pyproject = _pyproject_text()
        self.assertIn('"pypdf>=', pyproject)
        self.assertIn('"reportlab>=', pyproject)
        self.assertIn("[project.optional-dependencies]", pyproject)
        self.assertIn('"pytest>=', pyproject)

    def test_readme_documents_install_and_script_usage(self) -> None:
        readme = (SKILL_DIR / "README.md").read_text()
        self.assertIn("pip install -e '.[dev]'", readme)
        self.assertIn("python3 -m ensurepip --upgrade", readme)
        self.assertIn("python3 -m pip install --upgrade pip setuptools wheel", readme)
        self.assertIn("scripts/us-cpa", readme)
        self.assertIn("python -m unittest", readme)

    def test_docs_explain_openclaw_installation_flow(self) -> None:
        readme = (SKILL_DIR / "README.md").read_text()
        operator_doc = (SKILL_DIR.parent.parent / "docs" / "us-cpa.md").read_text()
        skill_doc = (SKILL_DIR / "SKILL.md").read_text()

        self.assertIn("OpenClaw installation", readme)
        self.assertIn("~/.openclaw/workspace/skills/us-cpa", readme)
        self.assertIn(".venv/bin/python", readme)
        self.assertIn("python3 -m ensurepip --upgrade", readme)
        self.assertIn("python3 -m pip install --upgrade pip setuptools wheel", readme)
        self.assertIn("--exclude '.venv'", readme)
        self.assertNotIn("/Users/stefano/", readme)
        self.assertIn("OpenClaw installation", operator_doc)
        self.assertIn("rsync -a --delete", operator_doc)
        self.assertIn("python3 -m ensurepip --upgrade", operator_doc)
        self.assertIn("python3 -m pip install --upgrade pip setuptools wheel", operator_doc)
        self.assertIn("--exclude '.venv'", operator_doc)
        self.assertIn("~/", operator_doc)
        self.assertNotIn("/Users/stefano/", operator_doc)
        self.assertIn("~/.openclaw/workspace/skills/us-cpa/scripts/us-cpa", skill_doc)

    def test_wrapper_prefers_local_virtualenv_python(self) -> None:
        wrapper = (SKILL_DIR / "scripts" / "us-cpa").read_text()
        self.assertIn('.venv/bin/python', wrapper)
        self.assertIn('PYTHON_BIN', wrapper)

    def test_fixture_directories_exist(self) -> None:
        fixtures_dir = SKILL_DIR / "tests" / "fixtures"
        for name in ("irs", "facts", "documents", "returns"):
            self.assertTrue((fixtures_dir / name).exists())

    def run_cli(self, *args: str) -> subprocess.CompletedProcess[str]:
        env = os.environ.copy()
        env["PYTHONPATH"] = str(SRC_DIR)
        return subprocess.run(
            [sys.executable, "-m", "us_cpa.cli", *args],
            text=True,
            capture_output=True,
            env=env,
        )

    def test_help_lists_all_commands(self) -> None:
        result = self.run_cli("--help")

        self.assertEqual(result.returncode, 0, result.stderr)
        for command in (
            "question",
            "prepare",
            "review",
            "fetch-year",
            "extract-docs",
            "render-forms",
            "export-efile-ready",
        ):
            self.assertIn(command, result.stdout)

    def test_question_command_emits_json_by_default(self) -> None:
        with tempfile.TemporaryDirectory() as temp_dir:
            env = os.environ.copy()
            env["PYTHONPATH"] = str(SRC_DIR)
            env["US_CPA_CACHE_DIR"] = temp_dir
            subprocess.run(
                [sys.executable, "-m", "us_cpa.cli", "fetch-year", "--tax-year", "2025"],
                text=True,
                capture_output=True,
                env=env,
                check=True,
            )
            result = subprocess.run(
                [
                    sys.executable,
                    "-m",
                    "us_cpa.cli",
                    "question",
                    "--tax-year",
                    "2025",
                    "--question",
                    "What is the standard deduction?",
                ],
                text=True,
                capture_output=True,
                env=env,
            )

        self.assertEqual(result.returncode, 0, result.stderr)
        payload = json.loads(result.stdout)
        self.assertEqual(payload["command"], "question")
        self.assertEqual(payload["format"], "json")
        self.assertEqual(payload["question"], "What is the standard deduction?")
        self.assertEqual(payload["status"], "answered")
        self.assertIn("analysis", payload)

    def test_prepare_requires_case_dir(self) -> None:
        result = self.run_cli("prepare", "--tax-year", "2025")

        self.assertNotEqual(result.returncode, 0)
        self.assertIn("case directory", result.stderr.lower())

    def test_extract_docs_can_create_case_and_register_facts(self) -> None:
        with tempfile.TemporaryDirectory() as temp_dir:
            case_dir = Path(temp_dir) / "2025-jane-doe"
            facts_path = Path(temp_dir) / "facts.json"
            facts_path.write_text(json.dumps({"filingStatus": "single"}))

            result = self.run_cli(
                "extract-docs",
                "--tax-year",
                "2025",
                "--case-dir",
                str(case_dir),
                "--create-case",
                "--case-label",
                "Jane Doe",
                "--facts-json",
                str(facts_path),
            )

            self.assertEqual(result.returncode, 0, result.stderr)
            payload = json.loads(result.stdout)
            self.assertEqual(payload["status"], "accepted")
            self.assertEqual(payload["factCount"], 1)
            self.assertTrue((case_dir / "case-manifest.json").exists())

    def test_extract_docs_stops_on_conflicts(self) -> None:
        with tempfile.TemporaryDirectory() as temp_dir:
            case_dir = Path(temp_dir) / "2025-jane-doe"
            first_facts = Path(temp_dir) / "facts-1.json"
            second_facts = Path(temp_dir) / "facts-2.json"
            first_facts.write_text(json.dumps({"filingStatus": "single"}))
            second_facts.write_text(json.dumps({"filingStatus": "married_filing_jointly"}))

            first = self.run_cli(
                "extract-docs",
                "--tax-year",
                "2025",
                "--case-dir",
                str(case_dir),
                "--create-case",
                "--case-label",
                "Jane Doe",
                "--facts-json",
                str(first_facts),
            )
            self.assertEqual(first.returncode, 0, first.stderr)

            second = self.run_cli(
                "extract-docs",
                "--tax-year",
                "2025",
                "--case-dir",
                str(case_dir),
                "--facts-json",
                str(second_facts),
            )
            self.assertNotEqual(second.returncode, 0)
            payload = json.loads(second.stdout)
            self.assertEqual(payload["status"], "needs_resolution")
            self.assertEqual(payload["issueType"], "fact_conflict")

    def test_question_markdown_memo_mode_renders_tax_memo(self) -> None:
        with tempfile.TemporaryDirectory() as temp_dir:
            env = os.environ.copy()
            env["PYTHONPATH"] = str(SRC_DIR)
            env["US_CPA_CACHE_DIR"] = temp_dir
            subprocess.run(
                [sys.executable, "-m", "us_cpa.cli", "fetch-year", "--tax-year", "2025"],
                text=True,
                capture_output=True,
                env=env,
                check=True,
            )
            result = subprocess.run(
                [
                    sys.executable,
                    "-m",
                    "us_cpa.cli",
                    "question",
                    "--tax-year",
                    "2025",
                    "--format",
                    "markdown",
                    "--style",
                    "memo",
                    "--question",
                    "What is the standard deduction?",
                ],
                text=True,
                capture_output=True,
                env=env,
            )

            self.assertEqual(result.returncode, 0, result.stderr)
            self.assertIn("# Tax Memo", result.stdout)
            self.assertIn("## Conclusion", result.stdout)

    def test_prepare_command_generates_return_package(self) -> None:
        with tempfile.TemporaryDirectory() as temp_dir:
            env = os.environ.copy()
            env["PYTHONPATH"] = str(SRC_DIR)
            env["US_CPA_CACHE_DIR"] = str(Path(temp_dir) / "cache")
            subprocess.run(
                [sys.executable, "-m", "us_cpa.cli", "fetch-year", "--tax-year", "2025"],
                text=True,
                capture_output=True,
                env=env,
                check=True,
            )

            case_dir = Path(temp_dir) / "2025-jane-doe"
            facts_path = Path(temp_dir) / "facts.json"
            facts_path.write_text(
                json.dumps(
                    {
                        "taxpayer.fullName": "Jane Doe",
                        "filingStatus": "single",
                        "wages": 50000,
                        "taxableInterest": 100,
                        "federalWithholding": 6000,
                    }
                )
            )
            subprocess.run(
                [
                    sys.executable,
                    "-m",
                    "us_cpa.cli",
                    "extract-docs",
                    "--tax-year",
                    "2025",
                    "--case-dir",
                    str(case_dir),
                    "--create-case",
                    "--case-label",
                    "Jane Doe",
                    "--facts-json",
                    str(facts_path),
                ],
                text=True,
                capture_output=True,
                env=env,
                check=True,
            )

            result = subprocess.run(
                [
                    sys.executable,
                    "-m",
                    "us_cpa.cli",
                    "prepare",
                    "--tax-year",
                    "2025",
                    "--case-dir",
                    str(case_dir),
                ],
                text=True,
                capture_output=True,
                env=env,
            )

            self.assertEqual(result.returncode, 0, result.stderr)
            payload = json.loads(result.stdout)
            self.assertEqual(payload["status"], "prepared")
            self.assertEqual(payload["summary"]["requiredForms"], ["f1040"])
            self.assertTrue((case_dir / "output" / "artifacts.json").exists())

    def test_review_command_returns_findings(self) -> None:
        with tempfile.TemporaryDirectory() as temp_dir:
            env = os.environ.copy()
            env["PYTHONPATH"] = str(SRC_DIR)
            env["US_CPA_CACHE_DIR"] = str(Path(temp_dir) / "cache")
            subprocess.run(
                [sys.executable, "-m", "us_cpa.cli", "fetch-year", "--tax-year", "2025"],
                text=True,
                capture_output=True,
                env=env,
                check=True,
            )
            case_dir = Path(temp_dir) / "2025-jane-doe"
            facts_path = Path(temp_dir) / "facts.json"
            facts_path.write_text(
                json.dumps(
                    {
                        "taxpayer.fullName": "Jane Doe",
                        "filingStatus": "single",
                        "wages": 50000,
                        "taxableInterest": 100,
                        "federalWithholding": 6000,
                    }
                )
            )
            subprocess.run(
                [
                    sys.executable,
                    "-m",
                    "us_cpa.cli",
                    "extract-docs",
                    "--tax-year",
                    "2025",
                    "--case-dir",
                    str(case_dir),
                    "--create-case",
                    "--case-label",
                    "Jane Doe",
                    "--facts-json",
                    str(facts_path),
                ],
                text=True,
                capture_output=True,
                env=env,
                check=True,
            )
            subprocess.run(
                [
                    sys.executable,
                    "-m",
                    "us_cpa.cli",
                    "prepare",
                    "--tax-year",
                    "2025",
                    "--case-dir",
                    str(case_dir),
                ],
                text=True,
                capture_output=True,
                env=env,
                check=True,
            )
            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))

            result = subprocess.run(
                [
                    sys.executable,
                    "-m",
                    "us_cpa.cli",
                    "review",
                    "--tax-year",
                    "2025",
                    "--case-dir",
                    str(case_dir),
                ],
                text=True,
                capture_output=True,
                env=env,
            )

            self.assertEqual(result.returncode, 0, result.stderr)
            payload = json.loads(result.stdout)
            self.assertEqual(payload["status"], "reviewed")
            self.assertEqual(payload["findingCount"], 2)


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