# -*- coding: utf-8 -*-
"""
area_section.py - 面单元截面属性定义
对应 SAP2000 的 PropArea

本模块用于定义截面属性（是什么），而非分配截面到面单元（怎么用）。
截面分配功能请使用 types_for_areas 模块。

包含三种类型：
- Shell (壳): 薄壳、厚壳、薄板、厚板、膜、分层壳
- Plane (平面): 平面应力、平面应变
- Asolid (轴对称实体)

Usage:
    from section import AreaSection, AreaSectionType, ShellType
    
    # 获取面属性
    prop = AreaSection.get_by_name(model, "SLAB1")
    print(f"类型: {prop.prop_type}, 厚度: {prop.thickness}")
    
    # 创建壳截面
    shell = AreaSection(
        name="SLAB1",
        shell_type=ShellType.SHELL_THIN,
        material="4000Psi",
        thickness=0.2
    )
    shell._create(model)
"""

from dataclasses import dataclass, field
from typing import Optional, List, ClassVar
from enum import IntEnum


class AreaSectionType(IntEnum):
    """面属性类型 - GetNameList 的 PropType 参数"""
    ALL = 0
    SHELL = 1
    PLANE = 2
    ASOLID = 3


class ShellType(IntEnum):
    """壳类型 - GetShell_1 的 ShellType 参数"""
    SHELL_THIN = 1
    SHELL_THICK = 2
    PLATE_THIN = 3
    PLATE_THICK = 4
    MEMBRANE = 5
    SHELL_LAYERED = 6


class PlaneType(IntEnum):
    """平面类型 - GetPlane 的 MyType 参数"""
    PLANE_STRESS = 1
    PLANE_STRAIN = 2


@dataclass
class AreaModifiers:
    """面属性修正系数(10个)"""
    f11: float = 1.0
    f22: float = 1.0
    f12: float = 1.0
    m11: float = 1.0
    m22: float = 1.0
    m12: float = 1.0
    v13: float = 1.0
    v23: float = 1.0
    mass: float = 1.0
    weight: float = 1.0
    
    def to_list(self) -> List[float]:
        """转换为列表"""
        return [self.f11, self.f22, self.f12, self.m11, self.m22, 
                self.m12, self.v13, self.v23, self.mass, self.weight]
    
    @classmethod
    def from_list(cls, values: List[float]) -> 'AreaModifiers':
        """从列表创建"""
        if len(values) >= 10:
            return cls(
                f11=values[0], f22=values[1], f12=values[2],
                m11=values[3], m22=values[4], m12=values[5],
                v13=values[6], v23=values[7],
                mass=values[8], weight=values[9]
            )
        return cls()


@dataclass
class AreaSection:
    """面单元截面属性 - 对应 SAP2000 PropArea"""
    
    name: str = ""
    prop_type: Optional[AreaSectionType] = None
    shell_type: Optional[ShellType] = None
    plane_type: Optional[PlaneType] = None
    material: str = ""
    thickness: float = 0.0
    bending_thickness: float = 0.0
    material_angle: float = 0.0
    include_drilling_dof: bool = False
    incompatible_modes: bool = True
    arc_angle: float = 360.0
    color: int = -1
    notes: str = ""
    guid: Optional[str] = None
    _object_type: ClassVar[str] = "PropArea"

    @classmethod
    def get_by_name(cls, model, name: str) -> 'AreaSection':
        """获取指定名称的面属性"""
        prop = cls(name=name)
        prop._get(model)
        return prop
    
    @classmethod
    def get_all(cls, model, prop_type: AreaSectionType = AreaSectionType.ALL) -> List['AreaSection']:
        """获取所有面属性"""
        names = cls.get_name_list(model, prop_type)
        props = []
        for name in names:
            try:
                prop = cls.get_by_name(model, name)
                props.append(prop)
            except Exception:
                pass
        return props
    
    @staticmethod
    def get_count(model) -> int:
        """获取面属性总数"""
        return model.PropArea.Count()
    
    @staticmethod
    def get_name_list(model, prop_type: AreaSectionType = AreaSectionType.ALL) -> List[str]:
        """获取面属性名称列表"""
        result = model.PropArea.GetNameList(0, [], prop_type.value)
        if isinstance(result, (list, tuple)) and len(result) >= 2:
            return list(result[1]) if result[1] else []
        return []
    
    def change_name(self, model, new_name: str) -> int:
        """修改属性名称"""
        ret = model.PropArea.ChangeName(self.name, new_name)
        if ret == 0:
            self.name = new_name
        return ret
    
    def get_modifiers(self, model) -> AreaModifiers:
        """获取修正系数"""
        result = model.PropArea.GetModifiers(self.name, [])
        if isinstance(result, (list, tuple)) and len(result) >= 2:
            values = result[0]
            if values and len(values) >= 10:
                return AreaModifiers.from_list(list(values))
        return AreaModifiers()
    
    def set_modifiers(self, model, modifiers: AreaModifiers) -> int:
        """设置修正系数"""
        return model.PropArea.SetModifiers(self.name, modifiers.to_list())

    def _get(self, model) -> 'AreaSection':
        """从 SAP2000 获取面属性数据"""
        result = model.PropArea.GetTypeOAPI(self.name)
        if isinstance(result, (list, tuple)) and len(result) >= 2:
            type_val = result[0]
            ret = result[1]
            if ret != 0:
                from exceptions import SectionError
                raise SectionError(f"面属性 {self.name} 不存在")
            try:
                self.prop_type = AreaSectionType(type_val)
            except ValueError:
                self.prop_type = AreaSectionType.SHELL
        else:
            from exceptions import SectionError
            raise SectionError(f"获取面属性 {self.name} 类型失败")
        
        if self.prop_type == AreaSectionType.SHELL:
            self._get_shell(model)
        elif self.prop_type == AreaSectionType.PLANE:
            self._get_plane(model)
        elif self.prop_type == AreaSectionType.ASOLID:
            self._get_asolid(model)
        return self
    
    def _get_shell(self, model):
        """获取壳属性数据"""
        result = model.PropArea.GetShell_1(self.name)
        if isinstance(result, (list, tuple)) and len(result) >= 10:
            try:
                self.shell_type = ShellType(result[0])
            except ValueError:
                self.shell_type = ShellType.SHELL_THIN
            self.include_drilling_dof = result[1]
            self.material = result[2] or ""
            self.material_angle = result[3]
            self.thickness = result[4]
            self.bending_thickness = result[5]
            self.color = result[6]
            self.notes = result[7] or ""
            self.guid = result[8] or None
    
    def _get_plane(self, model):
        """获取平面属性数据"""
        result = model.PropArea.GetPlane(self.name)
        if isinstance(result, (list, tuple)) and len(result) >= 9:
            try:
                self.plane_type = PlaneType(result[0])
            except ValueError:
                self.plane_type = PlaneType.PLANE_STRESS
            self.material = result[1] or ""
            self.material_angle = result[2]
            self.thickness = result[3]
            self.incompatible_modes = result[4]
            self.color = result[5]
            self.notes = result[6] or ""
            self.guid = result[7] or None
    
    def _get_asolid(self, model):
        """获取轴对称实体属性数据"""
        result = model.PropArea.GetAsolid(self.name)
        if isinstance(result, (list, tuple)) and len(result) >= 8:
            self.material = result[0] or ""
            self.material_angle = result[1]
            self.arc_angle = result[2]
            self.incompatible_modes = result[3]
            self.color = result[4]
            self.notes = result[5] or ""
            self.guid = result[6] or None

    def _create(self, model) -> int:
        """在 SAP2000 中创建面属性"""
        if self.shell_type is not None:
            return self._create_shell(model)
        elif self.plane_type is not None:
            return self._create_plane(model)
        elif self.prop_type == AreaSectionType.ASOLID:
            return self._create_asolid(model)
        else:
            self.shell_type = ShellType.SHELL_THIN
            return self._create_shell(model)
    
    def _create_shell(self, model) -> int:
        """创建壳属性"""
        return model.PropArea.SetShell_1(
            self.name,
            self.shell_type.value if self.shell_type else ShellType.SHELL_THIN.value,
            self.include_drilling_dof,
            self.material,
            self.material_angle,
            self.thickness,
            self.bending_thickness or self.thickness,
            self.color,
            self.notes,
            self.guid or ""
        )
    
    def _create_plane(self, model) -> int:
        """创建平面属性"""
        return model.PropArea.SetPlane(
            self.name,
            self.plane_type.value if self.plane_type else PlaneType.PLANE_STRESS.value,
            self.material,
            self.material_angle,
            self.thickness,
            self.incompatible_modes,
            self.color,
            self.notes,
            self.guid or ""
        )
    
    def _create_asolid(self, model) -> int:
        """创建轴对称实体属性"""
        return model.PropArea.SetAsolid(
            self.name,
            self.material,
            self.material_angle,
            self.arc_angle,
            self.incompatible_modes,
            self.color,
            self.notes,
            self.guid or ""
        )
    
    def _delete(self, model) -> int:
        """删除面属性"""
        return model.PropArea.Delete(self.name)
    
    def _update(self, model) -> int:
        """更新面属性"""
        return self._create(model)
