"""Data models for simulation system."""

from __future__ import annotations

import json
from dataclasses import dataclass, field
from datetime import datetime, timezone
from pathlib import Path


@dataclass
class ProjectInfo:
    """Project information dataclass."""

    name: str
    version: str = "1.0.0"
    created_date: datetime = field(default_factory=datetime.now)
    modified_date: datetime = field(default_factory=datetime.now)
    description: str = ""
    author: str = ""
    tags: list[str] = field(default_factory=list)

    def to_dict(self) -> dict:
        """Convert to dictionary for serialization."""
        return {
            "name": self.name,
            "version": self.version,
            "created_date": self.created_date.isoformat(),
            "modified_date": self.modified_date.isoformat(),
            "description": self.description,
            "author": self.author,
            "tags": self.tags,
        }

    @classmethod
    def from_dict(cls, data: dict) -> ProjectInfo:
        """Create ProjectInfo from dictionary."""
        return cls(
            name=data["name"],
            version=data.get("version", "1.0.0"),
            created_date=datetime.fromisoformat(data.get("created_date", datetime.now(tz=timezone.utc).isoformat())),
            modified_date=datetime.fromisoformat(data.get("modified_date", datetime.now(tz=timezone.utc).isoformat())),
            description=data.get("description", ""),
            author=data.get("author", ""),
            tags=data.get("tags", []),
        )


@dataclass
class SimulationProject:
    """Complete simulation project model."""

    info: ProjectInfo
    project_path: Path
    config_data: dict = field(default_factory=dict)
    simulation_data: dict = field(default_factory=dict)

    def save_to_file(self, file_path: Path | None = None) -> bool:
        """Save project to file."""
        try:
            save_path = file_path or self.project_path / f"{self.info.name}.lscsim"
            data = {
                "info": self.info.to_dict(),
                "config": self.config_data,
                "simulation": self.simulation_data,
            }
            with Path(save_path).open("w", encoding="utf-8") as f:
                json.dump(data, f, indent=2, ensure_ascii=False)
        except (OSError, UnicodeDecodeError, TypeError, ValueError):
            return False
        else:
            return True

    @classmethod
    def load_from_file(cls, file_path: Path) -> SimulationProject | None:
        """Load project from file."""
        try:
            with Path(file_path).open(encoding="utf-8") as f:
                data = json.load(f)

            info = ProjectInfo.from_dict(data["info"])
            return cls(
                info=info,
                project_path=file_path.parent,
                config_data=data.get("config", {}),
                simulation_data=data.get("simulation", {}),
            )
        except (OSError, UnicodeDecodeError, json.JSONDecodeError, KeyError, TypeError, ValueError):
            return None


@dataclass
class Material:
    """Material definition for simulation."""

    name: str
    density: float
    young_modulus: float
    poisson_ratio: float
    yield_strength: float
    description: str = ""

    def to_dict(self) -> dict:
        """Convert to dictionary."""
        return {
            "name": self.name,
            "density": self.density,
            "young_modulus": self.young_modulus,
            "poisson_ratio": self.poisson_ratio,
            "yield_strength": self.yield_strength,
            "description": self.description,
        }

    @classmethod
    def from_dict(cls, data: dict) -> Material:
        """Create Material from dictionary."""
        return cls(
            name=data["name"],
            density=data["density"],
            young_modulus=data["young_modulus"],
            poisson_ratio=data["poisson_ratio"],
            yield_strength=data["yield_strength"],
            description=data.get("description", ""),
        )


@dataclass
class SimulationTemplate:
    """Simulation template definition."""

    name: str
    template_data: dict
    description: str = ""
    created_date: datetime = field(default_factory=datetime.now)

    def to_dict(self) -> dict:
        """Convert to dictionary."""
        return {
            "name": self.name,
            "template_data": self.template_data,
            "description": self.description,
            "created_date": self.created_date.isoformat(),
        }

    @classmethod
    def from_dict(cls, data: dict) -> SimulationTemplate:
        """Create SimulationTemplate from dictionary."""
        return cls(
            name=data["name"],
            template_data=data["template_data"],
            description=data.get("description", ""),
            created_date=datetime.fromisoformat(data.get("created_date", datetime.now(tz=timezone.utc).isoformat())),
        )
