"""
Tests for the npm binary provider plugin.

Tests cover:
1. Hook script execution
2. npm package installation
3. PATH and NODE_MODULES_DIR updates
4. JSONL output format
"""

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

import pytest
from django.test import TestCase


# Get the path to the npm provider hook
PLUGIN_DIR = Path(__file__).parent.parent
INSTALL_HOOK = PLUGIN_DIR / 'on_Binary__install_using_npm_provider.py'


def npm_available() -> bool:
    """Check if npm is installed."""
    return shutil.which('npm') is not None


class TestNpmProviderHook(TestCase):
    """Test the npm binary provider installation hook."""

    def setUp(self):
        """Set up test environment."""
        self.temp_dir = tempfile.mkdtemp()
        self.lib_dir = Path(self.temp_dir) / 'lib' / 'x86_64-linux'
        self.lib_dir.mkdir(parents=True)

    def tearDown(self):
        """Clean up."""
        shutil.rmtree(self.temp_dir, ignore_errors=True)

    def test_hook_script_exists(self):
        """Hook script should exist."""
        self.assertTrue(INSTALL_HOOK.exists(), f"Hook not found: {INSTALL_HOOK}")

    def test_hook_requires_lib_dir(self):
        """Hook should fail when LIB_DIR is not set."""
        env = os.environ.copy()
        env.pop('LIB_DIR', None)  # Remove LIB_DIR

        result = subprocess.run(
            [
                sys.executable, str(INSTALL_HOOK),
                '--name=some-package',
                '--binary-id=test-uuid',
                '--machine-id=test-machine',
            ],
            capture_output=True,
            text=True,
            env=env,
            timeout=30
        )

        self.assertIn('LIB_DIR environment variable not set', result.stderr)
        self.assertEqual(result.returncode, 1)

    def test_hook_skips_when_npm_not_allowed(self):
        """Hook should skip when npm not in allowed binproviders."""
        env = os.environ.copy()
        env['LIB_DIR'] = str(self.lib_dir)

        result = subprocess.run(
            [
                sys.executable, str(INSTALL_HOOK),
                '--name=some-package',
                '--binary-id=test-uuid',
                '--machine-id=test-machine',
                '--binproviders=pip,apt',  # npm not allowed
            ],
            capture_output=True,
            text=True,
            env=env,
            timeout=30
        )

        # Should exit cleanly (code 0) when npm not allowed
        self.assertIn('npm provider not allowed', result.stderr)
        self.assertEqual(result.returncode, 0)

    @pytest.mark.skipif(not npm_available(), reason="npm not installed")
    def test_hook_creates_npm_prefix(self):
        """Hook should create npm prefix directory."""
        env = os.environ.copy()
        env['LIB_DIR'] = str(self.lib_dir)

        # Even if installation fails, the npm prefix should be created
        subprocess.run(
            [
                sys.executable, str(INSTALL_HOOK),
                '--name=nonexistent-xyz123',
                '--binary-id=test-uuid',
                '--machine-id=test-machine',
            ],
            capture_output=True,
            text=True,
            env=env,
            timeout=60
        )

        npm_prefix = self.lib_dir / 'npm'
        self.assertTrue(npm_prefix.exists())

    def test_hook_handles_overrides(self):
        """Hook should accept overrides JSON."""
        env = os.environ.copy()
        env['LIB_DIR'] = str(self.lib_dir)

        overrides = json.dumps({'npm': {'packages': ['custom-pkg']}})

        # Just verify it doesn't crash with overrides
        result = subprocess.run(
            [
                sys.executable, str(INSTALL_HOOK),
                '--name=test-pkg',
                '--binary-id=test-uuid',
                '--machine-id=test-machine',
                f'--overrides={overrides}',
            ],
            capture_output=True,
            text=True,
            env=env,
            timeout=60
        )

        # May fail to install, but should not crash parsing overrides
        self.assertNotIn('Failed to parse overrides JSON', result.stderr)


if __name__ == '__main__':
    pytest.main([__file__, '-v'])
