#!/usr/bin/env python3
"""
Shared utilities for test files to reduce code duplication
"""

import time
import unittest
from rich.console import Console
from rich.table import Table


class BaseTestCase(unittest.TestCase):
    """Base test case with common functionality"""

    @classmethod
    def setUpClass(cls):
        cls.console = Console()

    def setUp(self):
        self.start_time = time.time()

    def tearDown(self):
        elapsed_time = time.time() - self.start_time
        self.console.print(f"[dim]Completed in {elapsed_time:.2f}s[/dim]")

    def print_test_header(self, title):
        """Print formatted test header"""
        self.console.print(f"[bold magenta]{title}[/bold magenta]")

    def print_section_header(self, title):
        """Print formatted section header"""
        self.console.print(f"[bold blue]{title}[/bold blue]")

    def create_info_table(self, title, data):
        """Create and display an information table"""
        table = Table(title=title)
        table.add_column("Property", style="cyan")
        table.add_column("Value", style="green")

        for key, value in data.items():
            table.add_row(key, str(value))

        self.console.print(table)
        return table

    def create_results_table(self, title, results, columns=None):
        """Create and display a results table"""
        if not columns:
            columns = [("Name", "yellow"), ("Status", "bold"), ("Details", "green")]

        table = Table(title=title)
        for col_name, style in columns:
            table.add_column(col_name, style=style)

        for result in results:
            table.add_row(*[str(result.get(key, "-")) for key, _ in [(c[0].lower().replace(" ", "_"), c[1]) for c in columns]])

        self.console.print(table)
        return table

    def display_success_message(self, message):
        """Display success message"""
        self.console.print(f"[green]✅ {message}[/green]")

    def display_error_message(self, message):
        """Display error message"""
        self.console.print(f"[red]❌ {message}[/red]")

    def display_info_message(self, message):
        """Display info message"""
        self.console.print(f"[yellow]{message}[/yellow]")


class MoleculeTestMixin:
    """Mixin for molecule-related test functionality"""

    def validate_mol_desc_results(self, mol_desc, expect_success=True):
        """Validate MolDesc computation results"""
        if expect_success:
            self.assertIsNotNone(mol_desc.mol_props, "mol_props should not be None")
            self.assertIsNotNone(mol_desc.coord, "coord should not be None")
        return True

    def get_molecule_result_summary(self, mol_data, mol_desc, success, error=None):
        """Get standardized molecule result summary"""
        result = {"name": mol_data.get("name", "unknown"), "smiles": mol_data.get("smiles", ""), "success": success}

        if success and mol_desc:
            result.update(
                {
                    "properties": len(mol_desc.mol_props) if mol_desc.mol_props else 0,
                    "atom number": len(mol_desc.coord) if not mol_desc.coord.empty else 0,
                }
            )
        elif error:
            result["error"] = str(error)

        return result

    def display_molecule_result(self, result):
        """Display individual molecule result in standard format"""
        status_icon = "✓" if result["success"] else "✗"
        status_color = "green" if result["success"] else "red"

        data = {
            "SMILES": result["smiles"],
            "Status": f"[{status_color}]{status_icon} {'Success' if result['success'] else 'Failed'}[/{status_color}]",
        }

        if result["success"] and "properties" in result:
            data.update({"Properties": result["properties"], "Atom number": result["atom number"]})
        elif "error" in result:
            data["Error"] = result["error"]

        self.create_info_table(result["name"].title(), data)


class MultiMolTestMixin:
    """Mixin for MultiMolDesc-related test functionality"""

    def validate_multi_desc_loading(self, multi_desc):
        """Validate MultiMolDesc loading"""
        self.assertGreater(multi_desc.n_molecules, 0, "Should load molecules")
        return True

    def validate_multi_desc_computation(self, multi_desc):
        """Validate MultiMolDesc computation"""
        self.assertTrue(multi_desc.computed, "Computation should be complete")
        self.assertGreater(len(multi_desc.results), 0, "Should have results")
        return True

    def get_multi_desc_summary(self, multi_desc, df=None):
        """Get standardized MultiMolDesc summary"""
        successful = len(multi_desc.results)
        failed = len(multi_desc.failed_molecules)
        total_time = sum(multi_desc.computation_times.values()) if multi_desc.computation_times else 0

        summary = {
            "Total molecules": multi_desc.n_molecules,
            "Successful": successful,
            "Failed": failed,
            "Success rate": f"{(successful/(successful+failed)*100):.1f}%" if (successful + failed) > 0 else "N/A",
            "Total time": f"{total_time:.2f}s",
        }

        if df is not None:
            summary["DataFrame shape"] = f"{df.shape[0]}×{df.shape[1]}"

        if hasattr(multi_desc, "component_cache"):
            summary["Unique components computed"] = len(multi_desc.component_cache)

        return summary
