#!/usr/bin/env python3
"""
TDD tests for asset shipping in md-render command.

Tests the automatic copying of referenced assets when rendering markdown
to different output directories.
"""

import os
import tempfile
import pytest
from pathlib import Path
from unittest.mock import patch

from markitect.plugins.builtin.markdown_commands import md_render_command
from click.testing import CliRunner


class TestAssetShippingMdRender:
    """Test asset shipping functionality in md-render."""

    def setup_method(self):
        """Set up test environment."""
        self.runner = CliRunner()
        self.temp_dir = tempfile.mkdtemp()
        self.test_dir = Path(self.temp_dir)

        # Create test markdown with image references
        self.markdown_content = """# Test Document

## Images

![Architecture](images/arch.png)
![Logo](assets/logo.jpg)
![Diagram](./diagrams/flow.svg)

## Links

[Documentation](docs/readme.md)
"""

        # Create test file structure
        self.md_file = self.test_dir / "test.md"
        self.md_file.write_text(self.markdown_content)

        # Create asset directories and files
        (self.test_dir / "images").mkdir()
        (self.test_dir / "assets").mkdir()
        (self.test_dir / "diagrams").mkdir()
        (self.test_dir / "docs").mkdir()

        # Create sample asset files
        (self.test_dir / "images" / "arch.png").write_bytes(b"fake png data")
        (self.test_dir / "assets" / "logo.jpg").write_bytes(b"fake jpg data")
        (self.test_dir / "diagrams" / "flow.svg").write_text("<svg>fake svg</svg>")
        (self.test_dir / "docs" / "readme.md").write_text("# README")

    def teardown_method(self):
        """Clean up test environment."""
        import shutil
        shutil.rmtree(self.temp_dir, ignore_errors=True)

    def test_environment_variable_output_directory(self):
        """Test that MARKITECT_OUTPUT_DIR is used when no --output is specified."""
        output_dir = self.test_dir / "env_output"
        output_dir.mkdir()

        with patch.dict(os.environ, {'MARKITECT_OUTPUT_DIR': str(output_dir)}):
            result = self.runner.invoke(md_render_command, [str(self.md_file)])

        assert result.exit_code == 0
        assert (output_dir / "test.html").exists()

    def test_cli_output_overrides_environment_variable(self):
        """Test that CLI --output parameter overrides environment variable."""
        env_output = self.test_dir / "env_output"
        cli_output = self.test_dir / "cli_output"
        env_output.mkdir()
        cli_output.mkdir()

        with patch.dict(os.environ, {'MARKITECT_OUTPUT_DIR': str(env_output)}):
            result = self.runner.invoke(md_render_command, [
                str(self.md_file),
                '--output', str(cli_output)
            ])

        assert result.exit_code == 0
        assert (cli_output / "test.html").exists()
        assert not (env_output / "test.html").exists()

    def test_asset_shipping_enabled_by_default_for_directory_output(self):
        """Test that assets are shipped automatically when output is a directory."""
        output_dir = self.test_dir / "output"
        output_dir.mkdir()

        result = self.runner.invoke(md_render_command, [
            str(self.md_file),
            '--output', str(output_dir)
        ])

        assert result.exit_code == 0
        assert (output_dir / "test.html").exists()

        # Check that assets were copied
        assert (output_dir / "images" / "arch.png").exists()
        assert (output_dir / "assets" / "logo.jpg").exists()
        assert (output_dir / "diagrams" / "flow.svg").exists()
        assert (output_dir / "docs" / "readme.md").exists()

    def test_no_ship_assets_flag_suppresses_asset_copying(self):
        """Test that --no-ship-assets flag prevents asset copying."""
        output_dir = self.test_dir / "output"
        output_dir.mkdir()

        result = self.runner.invoke(md_render_command, [
            str(self.md_file),
            '--output', str(output_dir),
            '--no-ship-assets'
        ])

        assert result.exit_code == 0
        assert (output_dir / "test.html").exists()

        # Check that assets were NOT copied
        assert not (output_dir / "images").exists()
        assert not (output_dir / "assets").exists()
        assert not (output_dir / "diagrams").exists()

    def test_timestamp_based_asset_copying(self):
        """Test that assets are only copied if source is newer than destination."""
        output_dir = self.test_dir / "output"
        output_dir.mkdir()

        # First render - assets should be copied
        result = self.runner.invoke(md_render_command, [
            str(self.md_file),
            '--output', str(output_dir)
        ])
        assert result.exit_code == 0

        # Mark output asset as newer
        output_asset = output_dir / "images" / "arch.png"
        original_mtime = output_asset.stat().st_mtime
        output_asset.touch()  # Update timestamp

        # Second render - asset should not be overwritten
        result = self.runner.invoke(md_render_command, [
            str(self.md_file),
            '--output', str(output_dir)
        ])
        assert result.exit_code == 0

        # Check that the timestamp wasn't changed (asset wasn't overwritten)
        assert output_asset.stat().st_mtime > original_mtime

    def test_ship_assets_flag_explicit_enable(self):
        """Test that --ship-assets flag explicitly enables asset shipping."""
        output_dir = self.test_dir / "output"
        output_dir.mkdir()

        result = self.runner.invoke(md_render_command, [
            str(self.md_file),
            '--output', str(output_dir),
            '--ship-assets'
        ])

        assert result.exit_code == 0
        assert (output_dir / "test.html").exists()
        assert (output_dir / "images" / "arch.png").exists()

    def test_missing_assets_handled_gracefully(self):
        """Test that missing assets are handled with warnings, not errors."""
        # Remove one of the assets
        (self.test_dir / "images" / "arch.png").unlink()

        output_dir = self.test_dir / "output"
        output_dir.mkdir()

        result = self.runner.invoke(md_render_command, [
            str(self.md_file),
            '--output', str(output_dir)
        ])

        # Should succeed despite missing asset
        assert result.exit_code == 0
        assert (output_dir / "test.html").exists()

        # Other assets should still be copied
        assert (output_dir / "assets" / "logo.jpg").exists()

    def test_asset_discovery_from_markdown_content(self):
        """Test discovery of assets from markdown content."""
        from markitect.assets.discovery import discover_assets_from_markdown

        assets = discover_assets_from_markdown(self.markdown_content, self.test_dir)

        # Should find all asset references
        asset_paths = [asset.asset_path for asset in assets]
        assert "images/arch.png" in asset_paths
        assert "assets/logo.jpg" in asset_paths
        assert "./diagrams/flow.svg" in asset_paths
        assert "docs/readme.md" in asset_paths

    def test_relative_path_preservation(self):
        """Test that relative path structure is preserved in output."""
        output_dir = self.test_dir / "output"
        output_dir.mkdir()

        result = self.runner.invoke(md_render_command, [
            str(self.md_file),
            '--output', str(output_dir)
        ])

        assert result.exit_code == 0

        # Check that directory structure is preserved
        assert (output_dir / "images" / "arch.png").exists()
        assert (output_dir / "assets" / "logo.jpg").exists()
        assert (output_dir / "diagrams" / "flow.svg").exists()
        assert (output_dir / "docs" / "readme.md").exists()

    def test_asset_shipping_disabled_for_file_output(self):
        """Test that asset shipping is disabled when output is a specific file."""
        # Create a separate output directory
        output_dir = self.test_dir / "output_dir"
        output_dir.mkdir()
        output_file = output_dir / "specific_output.html"

        result = self.runner.invoke(md_render_command, [
            str(self.md_file),
            '--output', str(output_file)
        ])

        assert result.exit_code == 0
        assert output_file.exists()

        # Assets should NOT be copied when output is a specific file
        # (they should not exist in the output directory)
        assert not (output_dir / "images").exists()
        assert not (output_dir / "assets").exists()