# type: ignore
from sys import platform
import unittest
from unittest.mock import patch
from pathlib import Path
import tempfile
import shutil

from datetime import datetime, timezone

import pytest

from safety.tool.interceptors.unix import UnixAliasInterceptor


@pytest.mark.unix_only
@pytest.mark.skipif(
    platform not in ["linux", "linux2", "darwin"], reason="Unix-specific tests"
)
class TestUnixAliasInterceptor(unittest.TestCase):
    def setUp(self):
        self.temp_dir = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, self.temp_dir)

        self.mock_config_patcher = patch(
            "safety.tool.interceptors.unix.USER_CONFIG_DIR",
            Path(self.temp_dir) / ".safety",
        )
        self.mock_config_patcher.start()

        self.mock_home_patcher = patch("safety.tool.interceptors.unix.Path.home")
        self.mock_datetime_patcher = patch("safety.tool.interceptors.base.datetime")
        self.mock_version_patcher = patch("safety.tool.interceptors.base.get_version")

        self.mock_home = self.mock_home_patcher.start()
        self.mock_datetime = self.mock_datetime_patcher.start()
        self.mock_version = self.mock_version_patcher.start()

        self.mock_home.return_value = Path(self.temp_dir)
        self.mock_version.return_value = "1.0.0"
        self.mock_now = datetime(2024, 1, 1, tzinfo=timezone.utc)
        self.mock_datetime.now.return_value = self.mock_now

        self.addCleanup(self.mock_home_patcher.stop)
        self.addCleanup(self.mock_datetime_patcher.stop)
        self.addCleanup(self.mock_version_patcher.stop)
        self.addCleanup(self.mock_config_patcher.stop)

    def test_interceptors_all_tools(self):
        interceptor = UnixAliasInterceptor()
        result = interceptor.install_interceptors()

        self.assertTrue(result)

        rc_files = (".zshrc", ".bashrc", ".bash_profile")

        rc_paths = [Path(self.temp_dir) / rc for rc in rc_files]
        safety_profile_path = Path(self.temp_dir) / ".safety" / ".safety_profile"

        self.assertTrue(
            all(path.exists() for path in rc_paths), "Not all rc_paths exist"
        )
        self.assertTrue(safety_profile_path.exists())

        expected_rc_content = (
            "# >>> Safety >>>\n"
            f'[ -f "{safety_profile_path}" ] && . "{safety_profile_path}"\n'
            "# <<< Safety <<<\n"
        )

        expected_safety_profile_content = (
            "# >>> Safety >>>\n"
            "# DO NOT EDIT THIS FILE DIRECTLY\n"
            f"# Last updated at: {self.mock_now.isoformat()}\n"
            "# Updated by: safety v1.0.0\n"
            'alias pip="safety pip"\n'
            'alias pip3="safety pip3"\n'
            'alias pip3.8="safety pip3.8"\n'
            'alias pip3.9="safety pip3.9"\n'
            'alias pip3.10="safety pip3.10"\n'
            'alias pip3.11="safety pip3.11"\n'
            'alias pip3.12="safety pip3.12"\n'
            'alias pip3.13="safety pip3.13"\n'
            'alias pip3.14="safety pip3.14"\n'
            'alias poetry="safety poetry"\n'
            'alias uv="safety uv"\n'
            "# <<< Safety <<<\n"
        )

        for rc_path in rc_paths:
            self.assertEqual(rc_path.read_text(), expected_rc_content)

        self.assertEqual(
            safety_profile_path.read_text(), expected_safety_profile_content
        )

        result = interceptor.remove_interceptors()

        self.assertTrue(result)
        self.assertTrue(
            all(path.exists() for path in rc_paths), "Some rc_paths were removed"
        )

        for rc_path in rc_paths:
            self.assertEqual(rc_path.read_text(), "")

        self.assertFalse(safety_profile_path.exists())

    def test_install_interceptors_nonexistent_tool(self):
        interceptor = UnixAliasInterceptor()
        result = interceptor.install_interceptors(["nonexistent"])
        self.assertFalse(result)

    def test_uninstall_interceptors_all_tools(self):
        interceptor = UnixAliasInterceptor()
        result = interceptor.remove_interceptors()
        self.assertTrue(result)
