"""Tests for data models."""

from __future__ import annotations

import tempfile
from datetime import datetime
from pathlib import Path

import pytest

from pytola_sim.lscsim.models.project_model import (
    Material,
    ProjectInfo,
    SimulationProject,
    SimulationTemplate,
)


class TestProjectInfo:
    """Tests for ProjectInfo dataclass."""

    def test_creation(self) -> None:
        """Test project info creation."""
        info = ProjectInfo(name="test_project")
        assert info.name == "test_project"
        assert info.version == "1.0.0"
        assert isinstance(info.created_date, datetime)
        assert isinstance(info.modified_date, datetime)

    def test_to_dict(self) -> None:
        """Test conversion to dictionary."""
        info = ProjectInfo(
            name="test_project",
            version="2.0.0",
            description="Test description",
            author="Test Author",
            tags=["tag1", "tag2"],
        )
        data = info.to_dict()

        assert data["name"] == "test_project"
        assert data["version"] == "2.0.0"
        assert data["description"] == "Test description"
        assert data["author"] == "Test Author"
        assert data["tags"] == ["tag1", "tag2"]

    def test_from_dict(self) -> None:
        """Test creation from dictionary."""
        data = {
            "name": "test_project",
            "version": "1.5.0",
            "description": "Test desc",
            "author": "Author",
            "tags": ["test"],
        }
        info = ProjectInfo.from_dict(data)

        assert info.name == "test_project"
        assert info.version == "1.5.0"
        assert info.description == "Test desc"
        assert info.author == "Author"
        assert info.tags == ["test"]


class TestSimulationProject:
    """Tests for SimulationProject."""

    def test_save_and_load(self) -> None:
        """Test saving and loading project."""
        with tempfile.TemporaryDirectory() as temp_dir:
            project_path = Path(temp_dir)
            info = ProjectInfo(name="test_project")
            project = SimulationProject(
                info=info,
                project_path=project_path,
                config_data={"test": "config"},
                simulation_data={"test": "data"},
            )

            # Save project
            assert project.save_to_file()

            # Load project
            loaded_project = SimulationProject.load_from_file(project_path / "test_project.lscsim")

            assert loaded_project is not None
            assert loaded_project.info.name == "test_project"
            assert loaded_project.config_data == {"test": "config"}
            assert loaded_project.simulation_data == {"test": "data"}


class TestMaterial:
    """Tests for Material dataclass."""

    def test_creation(self) -> None:
        """Test material creation."""
        material = Material(
            name="Steel",
            density=7850.0,
            young_modulus=200e9,
            poisson_ratio=0.3,
            yield_strength=250e6,
            description="Structural steel",
        )

        assert material.name == "Steel"
        assert material.density == pytest.approx(7850.0)
        assert material.young_modulus == pytest.approx(200e9)
        assert material.poisson_ratio == pytest.approx(0.3)
        assert material.yield_strength == pytest.approx(250e6)
        assert material.description == "Structural steel"

    def test_to_dict_from_dict(self) -> None:
        """Test conversion to/from dictionary."""
        original = Material(
            name="Aluminum",
            density=2700.0,
            young_modulus=70e9,
            poisson_ratio=0.33,
            yield_strength=95e6,
        )

        # Convert to dict and back
        data = original.to_dict()
        restored = Material.from_dict(data)

        assert restored.name == original.name
        assert restored.density == pytest.approx(original.density)
        assert restored.young_modulus == pytest.approx(original.young_modulus)
        assert restored.poisson_ratio == pytest.approx(original.poisson_ratio)
        assert restored.yield_strength == pytest.approx(original.yield_strength)


class TestSimulationTemplate:
    """Tests for SimulationTemplate dataclass."""

    def test_creation(self) -> None:
        """Test template creation."""
        template_data = {"mesh_size": 0.1, "solver": "explicit"}
        template = SimulationTemplate(
            name="basic_template",
            template_data=template_data,
            description="Basic simulation template",
        )

        assert template.name == "basic_template"
        assert template.template_data == template_data
        assert template.description == "Basic simulation template"
        assert isinstance(template.created_date, datetime)

    def test_to_dict_from_dict(self) -> None:
        """Test conversion to/from dictionary."""
        original = SimulationTemplate(
            name="test_template",
            template_data={"param": "value"},
            description="Test template",
        )

        # Convert to dict and back
        data = original.to_dict()
        restored = SimulationTemplate.from_dict(data)

        assert restored.name == original.name
        assert restored.template_data == original.template_data
        assert restored.description == original.description
