"""Schema dataclasses for serialized airfoil definitions."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Literal


@dataclass(slots=True)
class Naca4AirfoilParamsSpec:
    """
    Explicit parameter definition for a NACA 4-digit airfoil.

    Attributes
    ----------
    m : float, default=0.0
        Maximum camber as a fraction of chord.
    p : float, default=0.0
        Chordwise location of maximum camber as a fraction of chord.
    t : float, default=0.0
        Maximum thickness as a fraction of chord.
    trailing_edge : {"standard", "sharp"}, default="standard"
        Trailing-edge closure model used for the thickness distribution.
    leading_edge_radius : {"standard", "exact"}, default="standard"
        Leading-edge radius treatment used for the thickness distribution.
    """

    m: float = 0.0
    p: float = 0.0
    t: float = 0.0
    trailing_edge: Literal["standard", "sharp"] = "standard"
    leading_edge_radius: Literal["standard", "exact"] = "standard"


@dataclass(slots=True)
class Naca4AirfoilSpec:
    """
    Classic NACA 4-digit airfoil definition.

    Attributes
    ----------
    type : Literal["naca4"], default="naca4"
        Schema discriminator for the NACA 4-digit family.
    designation : str or None, optional
        Classic 4-digit designation such as ``"2412"``.
    params : Naca4AirfoilParamsSpec or None, optional
        Explicit parameter override used instead of ``designation``.
    """

    type: Literal["naca4"] = "naca4"
    designation: str | None = None
    params: Naca4AirfoilParamsSpec | None = None


@dataclass(slots=True)
class Naca4ModifiedAirfoilParamsSpec:
    """
    Explicit parameter definition for a modified NACA 4-digit airfoil.

    Attributes
    ----------
    m : float, default=0.0
        Maximum camber as a fraction of chord.
    p : float, default=0.0
        Chordwise location of maximum camber as a fraction of chord.
    t : float, default=0.0
        Maximum thickness as a fraction of chord.
    leading_edge_index : float, default=1.0
        Modified-series leading-edge shape index.
    max_thickness_location : float, default=0.1
        Chordwise location of maximum thickness as a fraction of chord.
    trailing_edge : {"standard", "sharp"}, default="standard"
        Trailing-edge closure model used for the thickness distribution.
    """

    m: float = 0.0
    p: float = 0.0
    t: float = 0.0
    leading_edge_index: float = 1.0
    max_thickness_location: float = 0.1
    trailing_edge: Literal["standard", "sharp"] = "standard"


@dataclass(slots=True)
class Naca4ModifiedAirfoilSpec:
    """
    Modified NACA 4-digit airfoil definition.

    Attributes
    ----------
    type : Literal["naca4_modified"], default="naca4_modified"
        Schema discriminator for the modified NACA 4-digit family.
    designation : str or None, optional
        Modified-series designation string.
    params : Naca4ModifiedAirfoilParamsSpec or None, optional
        Explicit parameter override used instead of ``designation``.
    """

    type: Literal["naca4_modified"] = "naca4_modified"
    designation: str | None = None
    params: Naca4ModifiedAirfoilParamsSpec | None = None


@dataclass(slots=True)
class Naca5AirfoilParamsSpec:
    """
    Explicit parameter definition for a NACA 5-digit airfoil.

    Attributes
    ----------
    ideal_lift_coefficient : float, default=0.3
        Design lift coefficient associated with the mean camber line.
    max_camber_location : float, default=0.15
        Chordwise location of maximum camber as a fraction of chord.
    reflexed : bool, default=False
        Whether the camber line uses the reflexed 5-digit family.
    t : float, default=0.0
        Maximum thickness as a fraction of chord.
    trailing_edge : {"standard", "sharp"}, default="standard"
        Trailing-edge closure model used for the thickness distribution.
    leading_edge_radius : {"standard", "exact"}, default="standard"
        Leading-edge radius treatment used for the thickness distribution.
    """

    ideal_lift_coefficient: float = 0.3
    max_camber_location: float = 0.15
    reflexed: bool = False
    t: float = 0.0
    trailing_edge: Literal["standard", "sharp"] = "standard"
    leading_edge_radius: Literal["standard", "exact"] = "standard"


@dataclass(slots=True)
class Naca5AirfoilSpec:
    """
    NACA 5-digit airfoil definition.

    Attributes
    ----------
    type : Literal["naca5"], default="naca5"
        Schema discriminator for the NACA 5-digit family.
    designation : str or None, optional
        Classic 5-digit designation string.
    params : Naca5AirfoilParamsSpec or None, optional
        Explicit parameter override used instead of ``designation``.
    """

    type: Literal["naca5"] = "naca5"
    designation: str | None = None
    params: Naca5AirfoilParamsSpec | None = None


@dataclass(slots=True)
class Naca5ModifiedAirfoilParamsSpec:
    """
    Explicit parameter definition for a modified NACA 5-digit airfoil.

    Attributes
    ----------
    ideal_lift_coefficient : float, default=0.3
        Design lift coefficient associated with the mean camber line.
    max_camber_location : float, default=0.15
        Chordwise location of maximum camber as a fraction of chord.
    reflexed : bool, default=False
        Whether the camber line uses the reflexed 5-digit family.
    t : float, default=0.0
        Maximum thickness as a fraction of chord.
    leading_edge_index : float, default=1.0
        Modified-series leading-edge shape index.
    max_thickness_location : float, default=0.1
        Chordwise location of maximum thickness as a fraction of chord.
    trailing_edge : {"standard", "sharp"}, default="standard"
        Trailing-edge closure model used for the thickness distribution.
    """

    ideal_lift_coefficient: float = 0.3
    max_camber_location: float = 0.15
    reflexed: bool = False
    t: float = 0.0
    leading_edge_index: float = 1.0
    max_thickness_location: float = 0.1
    trailing_edge: Literal["standard", "sharp"] = "standard"


@dataclass(slots=True)
class Naca5ModifiedAirfoilSpec:
    """
    Modified NACA 5-digit airfoil definition.

    Attributes
    ----------
    type : Literal["naca5_modified"], default="naca5_modified"
        Schema discriminator for the modified NACA 5-digit family.
    designation : str or None, optional
        Modified-series designation string.
    params : Naca5ModifiedAirfoilParamsSpec or None, optional
        Explicit parameter override used instead of ``designation``.
    """

    type: Literal["naca5_modified"] = "naca5_modified"
    designation: str | None = None
    params: Naca5ModifiedAirfoilParamsSpec | None = None


@dataclass(slots=True)
class DatAirfoilSpec:
    """
    Airfoil loaded from a DAT file.

    Attributes
    ----------
    type : Literal["dat"], default="dat"
        Schema discriminator for a DAT-backed airfoil definition.
    path : str, default=""
        Path to the DAT file containing the airfoil coordinates.
    """

    type: Literal["dat"] = "dat"
    path: str = ""


@dataclass(slots=True)
class CstSurfaceSpec:
    """
    CST coefficient set for one airfoil surface.

    Attributes
    ----------
    n1 : float
        Leading-edge class function exponent.
    n2 : float
        Trailing-edge class function exponent.
    a : list[float], optional
        Shape-function coefficients for the surface polynomial basis.
    """

    n1: float
    n2: float
    a: list[float] = field(default_factory=list)


@dataclass(slots=True)
class CstAirfoilSpec:
    """
    CST airfoil definition.

    Attributes
    ----------
    type : Literal["cst"], default="cst"
        Schema discriminator for a CST airfoil definition.
    upper : CstSurfaceSpec, optional
        CST coefficients for the upper surface.
    lower : CstSurfaceSpec, optional
        CST coefficients for the lower surface.
    """

    type: Literal["cst"] = "cst"
    upper: CstSurfaceSpec = field(
        default_factory=lambda: CstSurfaceSpec(0.5, 1.0)
    )
    lower: CstSurfaceSpec = field(
        default_factory=lambda: CstSurfaceSpec(0.5, 1.0)
    )


type AirfoilDefinitionSpec = (
    Naca4AirfoilSpec
    | Naca4ModifiedAirfoilSpec
    | Naca5AirfoilSpec
    | Naca5ModifiedAirfoilSpec
    | DatAirfoilSpec
    | CstAirfoilSpec
)


__all__ = [
    "AirfoilDefinitionSpec",
    "CstAirfoilSpec",
    "CstSurfaceSpec",
    "DatAirfoilSpec",
    "Naca4AirfoilParamsSpec",
    "Naca4AirfoilSpec",
    "Naca4ModifiedAirfoilParamsSpec",
    "Naca4ModifiedAirfoilSpec",
    "Naca5AirfoilParamsSpec",
    "Naca5AirfoilSpec",
    "Naca5ModifiedAirfoilParamsSpec",
    "Naca5ModifiedAirfoilSpec",
]
