import json
import shutil
import sys
import unittest
from datetime import datetime
from pathlib import Path

PROJECT_ROOT = Path(__file__).resolve().parent.parent
if str(PROJECT_ROOT) not in sys.path:
    sys.path.insert(0, str(PROJECT_ROOT))

from core.io.compressor import CompressionError, compress_bsp


class TestCSSModCompressor(unittest.TestCase):
    """Sandbox unit testing system for the BSP compression module."""

    def setUp(self):
        """Initialize the sandbox environment before each test."""
        self.results_sandbox = Path(__file__).parent / "results_sandbox"
        self.source_dir = self.results_sandbox / "maptest"
        self.dest_dir = self.results_sandbox / "maptestcompressed"
        self.reports_dir = self.results_sandbox / "results"

        # Création des dossiers de la Sandbox
        self.source_dir.mkdir(parents=True, exist_ok=True)
        self.dest_dir.mkdir(parents=True, exist_ok=True)
        self.reports_dir.mkdir(parents=True, exist_ok=True)

        # Génération de fichiers factices pour les scénarios de test
        self.valid_bsp = self.source_dir / "de_dust2_test.bsp"
        self.valid_bsp.write_bytes(b"Fake BSP content data binary 12345")

        self.invalid_file = self.source_dir / "bad_extension.txt"
        self.invalid_file.write_text("Ceci n'est pas un fichier BSP", encoding="utf-8")

        # Initialisation de la structure du rapport global comme le script d'origine
        self.report = {
            "generated_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "success": [],
            "errors": [],
            "summary": {},
        }

    def tearDown(self):
        """Thorough cleaning and removal of the sandbox after each test."""
        if self.results_sandbox.exists():
            shutil.rmtree(self.results_sandbox)

    def test_compress_valid_bsp(self):
        """Verifies that a valid .bsp file is successfully compressed into a .bz2 file."""
        destination_file = self.dest_dir / f"{self.valid_bsp.name}.bz2"

        result_path = compress_bsp(self.valid_bsp, destination_file)

        self.assertTrue(destination_file.exists(), "Le fichier compressé .bz2 n'a pas été créé.")
        self.assertEqual(result_path, destination_file)
        self.assertGreater(destination_file.stat().st_size, 0, "Le fichier compressé est vide.")

        self.report["success"].append(
            {
                "file": self.valid_bsp.name,
                "source_size": self.valid_bsp.stat().st_size,
                "compressed_size": destination_file.stat().st_size,
            }
        )
        self._write_report_summary(success_count=1, error_count=0)

    def test_compress_invalid_extension(self):
        """Verify that compressing a non-.bsp file raises a CompressionError."""
        destination_file = self.dest_dir / f"{self.invalid_file.name}.bz2"

        with self.assertRaises(CompressionError) as context:
            compress_bsp(self.invalid_file, destination_file)

        self.assertIn("The file must be a .bsp file", str(context.exception))

        self.report["errors"].append(
            {
                "file": self.invalid_file.name,
                "error_type": type(context.exception).__name__,
                "error_message": str(context.exception),
            }
        )
        self._write_report_summary(success_count=0, error_count=1)

    def test_compress_non_existent_file(self):
        """Verify that attempting to compress a file that cannot be found raises a FileNotFoundError."""
        ghost_file = self.source_dir / "de_ghost_map.bsp"
        destination_file = self.dest_dir / f"{ghost_file.name}.bz2"

        with self.assertRaises(FileNotFoundError):
            compress_bsp(ghost_file, destination_file)

    def _write_report_summary(self, success_count: int, error_count: int):
        """Internal utility method for serializing the final JSON report in the Sandbox."""
        self.report["summary"] = {
            "success_count": success_count,
            "error_count": error_count,
            "total_files": success_count + error_count,
        }
        timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
        report_file = self.reports_dir / f"compressor_report_{timestamp}.json"

        with report_file.open("w", encoding="utf-8") as f:
            json.dump(self.report, f, indent=4, ensure_ascii=False)

        self.assertTrue(report_file.exists())


if __name__ == "__main__":
    unittest.main()
