# Familiar - Self-Hosted AI Companion Platform
# Copyright (c) 2026 George Scott Foley
# ORCID: 0009-0006-4957-0540
# Email: Georgescottfoley@proton.me
# Licensed under the MIT License - see LICENSE file for details

"""Tests for the Office Suite: bundled templates, charts skill, presentations."""

import json
from unittest.mock import patch

import pytest


def _matplotlib_available():
    try:
        import matplotlib  # noqa: F401

        return True
    except ImportError:
        return False


def _pptx_available():
    try:
        import pptx  # noqa: F401

        return True
    except ImportError:
        return False


# ── Bundled Templates ────────────────────────────────────────────────


class TestBundledTemplates:
    """Tests for bundled JSON templates shipped with the documents skill."""

    def test_templates_directory_exists(self):
        from familiar.skills.documents.skill import BUNDLED_TEMPLATES_DIR

        assert BUNDLED_TEMPLATES_DIR.exists(), "Bundled templates directory missing"
        assert BUNDLED_TEMPLATES_DIR.is_dir()

    def test_template_count(self):
        from familiar.skills.documents.skill import BUNDLED_TEMPLATES_DIR

        templates = list(BUNDLED_TEMPLATES_DIR.glob("*.json"))
        assert len(templates) >= 27, f"Expected 27+ templates, found {len(templates)}"

    def test_all_templates_valid_json(self):
        from familiar.skills.documents.skill import BUNDLED_TEMPLATES_DIR

        for f in BUNDLED_TEMPLATES_DIR.glob("*.json"):
            with open(f) as fh:
                data = json.load(fh)
            assert "description" in data, f"{f.name} missing 'description'"
            assert "content" in data, f"{f.name} missing 'content'"
            assert "job_class" in data, f"{f.name} missing 'job_class'"

    def test_all_job_classes_represented(self):
        from familiar.skills.documents.skill import BUNDLED_TEMPLATES_DIR

        classes = set()
        for f in BUNDLED_TEMPLATES_DIR.glob("*.json"):
            with open(f) as fh:
                data = json.load(fh)
            classes.add(data.get("job_class"))
        expected = {
            "helper",
            "social_worker",
            "business_buddy",
            "nonprofit_director",
            "chef",
            "artist",
        }
        assert expected.issubset(classes), f"Missing job classes: {expected - classes}"

    def test_list_templates_includes_bundled(self):
        from familiar.skills.documents.skill import list_templates

        result = list_templates({})
        assert "Bundled Templates:" in result
        assert "helper_research_brief" in result
        assert "chef_recipe_card" in result
        assert "artist_commission_agreement" in result

    def test_fill_template_finds_bundled(self):
        from familiar.skills.documents.skill import fill_template

        result = fill_template(
            {
                "template": "helper_research_brief",
                "fields": {
                    "title": "Test Brief",
                    "research_question": "Does it work?",
                    "findings": "Yes",
                    "sources": "Tests",
                    "recommendations": "Ship it",
                },
            }
        )
        assert "Document created from template" in result or "helper_research_brief" in result

    def test_user_template_overrides_bundled(self):
        """User templates in ~/.familiar/templates/ should override bundled ones."""
        from familiar.skills.documents.skill import TEMPLATES_DIR, fill_template

        TEMPLATES_DIR.mkdir(parents=True, exist_ok=True)
        override = TEMPLATES_DIR / "helper_research_brief.json"
        try:
            override.write_text(
                json.dumps(
                    {
                        "description": "User override",
                        "job_class": "helper",
                        "content": {
                            "title": "Override: {{title}}",
                            "sections": [{"heading": "Custom", "body": "{{body}}"}],
                        },
                    }
                )
            )
            result = fill_template(
                {
                    "template": "helper_research_brief",
                    "fields": {"title": "Overridden", "body": "Custom content"},
                }
            )
            assert "Document created from template" in result
        finally:
            if override.exists():
                override.unlink()


# ── Charts Skill ─────────────────────────────────────────────────────


class TestCharts:
    """Tests for the charts skill."""

    def test_tools_defined(self):
        from familiar.skills.charts.skill import TOOLS

        names = [t["name"] for t in TOOLS]
        assert "create_chart" in names
        assert "create_chart_from_data" in names

    def test_create_chart_missing_values(self):
        from familiar.skills.charts.skill import create_chart

        result = create_chart({"title": "Test", "labels": ["A", "B"]})
        assert "provide" in result.lower() or "values" in result.lower()

    def test_create_chart_missing_labels(self):
        from familiar.skills.charts.skill import create_chart

        result = create_chart({"title": "Test", "values": [1, 2]})
        assert "provide" in result.lower() or "labels" in result.lower()

    def test_create_chart_from_data_bad_dataset(self):
        from familiar.skills.charts.skill import create_chart_from_data

        result = create_chart_from_data({"dataset": "nonexistent"})
        assert "Unknown dataset" in result

    @pytest.mark.skipif(not _matplotlib_available(), reason="matplotlib not installed")
    def test_render_chart_bytes_returns_bytes(self):
        from familiar.skills.charts.skill import render_chart_bytes

        result = render_chart_bytes(
            chart_type="bar",
            title="Test",
            labels=["A", "B", "C"],
            values=[10, 20, 30],
        )
        assert isinstance(result, bytes)
        assert len(result) > 0

    @pytest.mark.skipif(not _matplotlib_available(), reason="matplotlib not installed")
    def test_pie_chart_renders(self):
        from familiar.skills.charts.skill import render_chart_bytes

        result = render_chart_bytes(
            chart_type="pie",
            title="Distribution",
            labels=["X", "Y", "Z"],
            values=[40, 35, 25],
        )
        assert isinstance(result, bytes)

    @pytest.mark.skipif(not _matplotlib_available(), reason="matplotlib not installed")
    def test_line_chart_renders(self):
        from familiar.skills.charts.skill import render_chart_bytes

        result = render_chart_bytes(
            chart_type="line",
            title="Trend",
            labels=["Jan", "Feb", "Mar"],
            values=[100, 150, 200],
        )
        assert isinstance(result, bytes)


# ── Presentations ────────────────────────────────────────────────────


class TestPresentation:
    """Tests for the create_presentation tool."""

    def test_empty_slides_returns_error(self):
        from familiar.skills.documents.skill import create_presentation

        result = create_presentation({"title": "Test", "slides": []})
        assert "provide slides" in result.lower()

    def test_fallback_to_docx_when_pptx_unavailable(self):
        from familiar.skills.documents import skill as doc_skill

        original = doc_skill.PPTX_AVAILABLE
        try:
            doc_skill.PPTX_AVAILABLE = False
            with patch.object(doc_skill, "_ensure_pptx", return_value=False):
                result = doc_skill.create_presentation(
                    {
                        "title": "Fallback Test",
                        "slides": [
                            {"type": "content", "title": "Slide 1", "bullets": ["Point A"]},
                        ],
                    }
                )
                assert "DOCX" in result or "docx" in result
        finally:
            doc_skill.PPTX_AVAILABLE = original

    @pytest.mark.skipif(not _pptx_available(), reason="python-pptx not installed")
    def test_valid_slides_produce_pptx(self):
        from familiar.skills.documents.skill import create_presentation

        result = create_presentation(
            {
                "title": "Integration Test",
                "layout": "report",
                "slides": [
                    {"type": "title", "title": "Hello", "body": "World"},
                    {"type": "content", "title": "Points", "bullets": ["A", "B", "C"]},
                    {"type": "section", "title": "Next Section"},
                ],
            }
        )
        assert "Presentation created" in result
        assert ".pptx" in result
