from __future__ import annotations
from dataclasses import dataclass
from typing import Any, List, TYPE_CHECKING

from zempy.zosapi.analysis.adapters.message import  Message
from zempy.zosapi.systemdata.field.field import Field
from zempy.zosapi.systemdata.field.field_type import FieldType

if TYPE_CHECKING:
    from zempy.zosapi.system.protocols.IOpticalSystem import IOpticalSystem

def get_fields(system: IOpticalSystem):
    return system.system_data.Fields

@dataclass(frozen=True, slots=True)
class Fields:
    system: IOpticalSystem

    @property
    def _ifields(self) -> Any:
        return get_fields(self.system)

    @property
    def number_of_fields(self) -> int:
        return int(self._ifields.NumberOfFields)

    def __len__(self) -> int:
        return self.number_of_fields

    # --- get / add / insert return ZOSSystemField (not raw) ---
    def get(self, position: int) -> Field:
        ifield = self._ifields.GetField(int(position))
        return Field(system= self.system, _ifield= ifield)

    def add_field(self, x: float, y: float, weight: float = 1.0) -> Field:
        ifield = self._ifields.AddField(float(x), float(y), float(weight))
        return Field(system= self.system, _ifield= ifield)

    def insert_field_at(self, field_number: int) -> Field:
        ifield = self._ifields.InsertFieldAt(int(field_number))
        return Field(system=self.system, _ifield=ifield)

    # Optional: aliases for symmetry
    add = add_field
    insert_at = insert_field_at

    # --- remove / delete ---
    def remove_field(self, position: int) -> bool:
        return bool(self._ifields.RemoveField(int(position)))

    def delete_field_at(self, field_number: int) -> bool:
        return bool(self._ifields.DeleteFieldAt(int(field_number)))

    def delete_fields_at(self, field_number: int, number_of_fields: int) -> int:
        return int(self._ifields.DeleteFieldsAt(int(field_number), int(number_of_fields)))

    def delete_all(self) -> int:
        return int(self._ifields.DeleteAllFields())

    # --- vignetting ---
    def set_vignetting(self) -> None:
        self._ifields.SetVignetting()

    def clear_vignetting(self) -> None:
        self._ifields.ClearVignetting()

    # --- field type via your helpers ---
    def set_type(self, ft: FieldType) -> None:
        native = FieldType.to_native(value=ft, zosapi=self.system.zosapi)
        self.system.system_data.Fields.SetFieldType(native)

    def get_type(self) -> FieldType:
        raw = self.system.system_data.Fields.GetFieldType()
        return FieldType.from_native(raw=raw, zosapi=self.system.zosapi)

    def convert_to_type(self, ft: FieldType) -> Message:
        native = FieldType.to_native(value=ft, zosapi=self.system.zosapi)
        zos_message = self._ifields.ConvertToFieldType(native)
        return Message.from_zos(zos_message)

    # --- wizards / patterns ---
    def make_equal_area(self, number_of_fields: int, maximum_field: float) -> bool:
        return bool(self._ifields.MakeEqualAreaFields(int(number_of_fields), float(maximum_field)))

    def apply_wizard(
        self,
        pattern: Any,
        number_of_y_fields: int,
        max_field_y: float,
        number_of_x_fields: int,
        max_field_x: float,
        start_at: int = 1,
        overwrite: bool = False,
        include_pickups: bool = True,
    ) -> Message:
        zos_message = self._ifields.ApplyFieldWizard(
            pattern,
            int(number_of_y_fields), float(max_field_y),
            int(number_of_x_fields), float(max_field_x),
            int(start_at), bool(overwrite), bool(include_pickups),
        )
        return Message.from_zos(zos_message)

    # --- normalization ---
    @property
    def normalization(self) -> Any:
        return self._ifields.Normalization

    @normalization.setter
    def normalization(self, value: Any) -> None:
        self._ifields.Normalization = value

    # --- convenience ---
    def last_index(self) -> int:
        return self.number_of_fields

    def indices(self) -> range:
        return range(1, self.number_of_fields + 1)

    def as_list(self) -> List[Field]:
        return [self.get(i) for i in self.indices()]
