"""
ctypes structure definitions for the SQ API.

This module contains all ctypes Structure definitions that correspond to
the Delphi record types used by the Siroquant DLL. These structures are
used internally for communication with the DLL and are typically converted
to Pythonic dataclasses for user-facing code.

For most users, the dataclasses in pysq.dataclasses are preferred over
these ctypes structures. However, these structures are exported for
backward compatibility and advanced use cases.

Example:
    >>> from pysq.types import TUnitCell
    >>> cell = TUnitCell()
    >>> cell.A = 5.0
    >>> cell.B = 5.0
    >>> cell.C = 5.0
    >>> cell.alpha = 90.0
    >>> cell.beta = 90.0
    >>> cell.gamma = 90.0
"""

from ctypes import c_int, c_double, c_char_p, c_void_p, c_long, c_bool, Structure, POINTER, c_char
from .constants import cmaxphases, cmaxtracepoints

# Types
TZeroOne = c_int  # 0..1
TRealZeroOne = c_double * 2


class TUnitCell(Structure):
    """
    ctypes structure for unit cell parameters.
    
    Corresponds to the Delphi TUnitCell record type. Contains six parameters
    defining a crystal unit cell: three edge lengths and three angles.
    
    Attributes:
        A: Unit cell edge length a (c_double).
        B: Unit cell edge length b (c_double).
        C: Unit cell edge length c (c_double).
        alpha: Angle between b and c axes in degrees (c_double).
        beta: Angle between a and c axes in degrees (c_double).
        gamma: Angle between a and b axes in degrees (c_double).
    
    Note:
        Prefer using pysq.dataclasses.UnitCell for most use cases.
    """
    _fields_ = [
        ("A", c_double),
        ("B", c_double),
        ("C", c_double),
        ("alpha", c_double),
        ("beta", c_double),
        ("gamma", c_double),
    ]


class Tuvw(Structure):
    """
    ctypes structure for UVW (Caglioti) parameters.
    
    Corresponds to the Delphi Tuvw record type. Contains the UVW parameters
    used for peak profile fitting in Rietveld refinement.
    
    Attributes:
        u: U parameter (c_double).
        v: V parameter (c_double).
        w: W parameter (c_double).
    
    Note:
        Prefer using pysq.dataclasses.UVW for most use cases.
    """
    _pack_ = 1  # Packed record
    _fields_ = [
        ("u", c_double),
        ("v", c_double),
        ("w", c_double),
    ]


T12uvw = Tuvw * 2


class TOpenTaskRec(Structure):
    """
    ctypes structure for task opening information.
    
    Returned by SQ4OpenTask1 and SQ4OpenTask2 functions. Contains information
    about the opened task file.
    
    Attributes:
        numberPhases: Number of phases in the task (c_int).
        Numberpoints: Number of data points in the task (c_int).
        flags: Task flags (c_long).
        return_val: Return code from opening (c_int). Negative values indicate errors.
    
    Note:
        Prefer using pysq.dataclasses.TaskInfo for most use cases.
    """
    _fields_ = [
        ("numberPhases", c_int),
        ("Numberpoints", c_int),
        ("flags", c_long),
        ("return_val", c_int),  # renamed from 'return'
    ]


class TLoadPatternRec(Structure):
    """
    ctypes structure for pattern loading information.
    
    Returned by SQ4LoadPattern1 and SQ4LoadPattern2 functions. Contains
    information about the loaded pattern file.
    
    Attributes:
        patterntype: Type of pattern format (c_int).
        patternNo: Pattern number assigned by the system (c_int).
        Numberpoints: Number of data points in the pattern (c_int).
        flags: Pattern flags (c_long).
        return_val: Return code from loading (c_int). Negative values indicate errors.
    
    Note:
        Prefer using pysq.dataclasses.PatternInfo for most use cases.
    """
    _fields_ = [
        ("patterntype", c_int),
        ("patternNo", c_int),
        ("Numberpoints", c_int),
        ("flags", c_long),
        ("return_val", c_int),
    ]


class TStartRefinementRec(Structure):
    """
    ctypes structure for refinement parameters.
    
    Used by SQ4StartRefinement function to specify refinement parameters.
    Contains all settings needed to start a refinement operation.
    
    Attributes:
        nAutoPrescale: Number of automatic prescaling iterations (c_int).
        nRefs: Number of refinement iterations (c_int).
        cutoff: Cutoff value for refinement (c_double).
        ErrorCutoff: Error cutoff value (c_double).
        ErrorPC: Error percentage threshold (c_double).
        flags: Refinement flags (c_long).
        RetFlags: Return flags set by refinement (c_int).
    
    Note:
        Prefer using pysq.dataclasses.RefinementParams for most use cases.
    """
    _fields_ = [
        ("nAutoPrescale", c_int),
        ("nRefs", c_int),
        ("cutoff", c_double),
        ("ErrorCutoff", c_double),
        ("ErrorPC", c_double),
        ("flags", c_long),
        ("RetFlags", c_int),
    ]


# Delphi ShortString: 1 byte length + chars. string[31] = 32 bytes.
class DelphiString31(Structure):
    """
    ctypes structure for Delphi ShortString[31] type.
    
    Delphi ShortString is a Pascal-style string with a length byte followed
    by the string content. This structure represents a string of up to 31
    characters (plus length byte = 32 bytes total).
    
    Attributes:
        length: Length byte (c_char, actually a byte).
        content: String content, up to 31 characters (c_char * 31).
    
    Note:
        This is automatically converted to Python str in dataclasses.
        The __str__ method handles the conversion.
    """
    _fields_ = [
        ("length", c_char),  # Actually byte, but c_char is 1 byte
        ("content", c_char * 31),
    ]
    
    def __str__(self):
        """Convert Delphi ShortString to Python string."""
        l = ord(self.length)
        return self.content[:l].decode('latin1')


class TSearchMatchRec(Structure):
    """
    ctypes structure for search/match result.
    
    Contains information about a phase identified during a search/match
    operation against the phase database.
    
    Attributes:
        PhaseID: Phase identifier (c_int).
        PhaseName: Name of the phase (DelphiString31).
        Status: Status string (DelphiString31).
        WeightPC: Weight percentage (c_double).
        ErrorOfFit: Error of fit (c_double).
    
    Note:
        Prefer using pysq.dataclasses.SearchMatchResult for most use cases.
    """
    _fields_ = [
        ("PhaseID", c_int),
        ("PhaseName", DelphiString31),
        ("Status", DelphiString31),
        ("WeightPC", c_double),
        ("ErrorOfFit", c_double),
    ]


class TSearchMatchCondition(Structure):
    """
    ctypes structure for search/match conditions.
    
    Used to specify criteria for phase search/match operations.
    
    Attributes:
        cutoff: Cutoff value for matching (c_double).
        ErrorCutoff: Error cutoff value (c_double).
        ErrorPC: Error percentage threshold (c_double).
    """
    _fields_ = [
        ("cutoff", c_double),
        ("ErrorCutoff", c_double),
        ("ErrorPC", c_double),
    ]


ASearchMatchRec = TSearchMatchRec * cmaxphases
PASearchMatchRec = POINTER(ASearchMatchRec)


class TReportRec(Structure):
    """
    ctypes structure for refinement report.
    
    Contains overall statistics from a refinement operation.
    
    Attributes:
        ChiSQ: Chi-squared value of the fit (c_double).
        Rfactor: R-factor (Rietveld R-value) of the fit (c_double).
        nPhases: Number of phases in the result (c_int).
        flags: Report flags (c_long).
    """
    _fields_ = [
        ("ChiSQ", c_double),
        ("Rfactor", c_double),
        ("nPhases", c_int),
        ("flags", c_long),
    ]


class TResultRec(Structure):
    """
    ctypes structure for individual phase result.
    
    Contains the quantitative phase analysis result for a single phase.
    
    Attributes:
        WeightPC: Weight percentage of the phase (c_double).
        ErrorOfFit: Error of fit for the phase (c_double).
        OrderNo: Order number (c_int).
        PhaseID: Phase identifier (c_int).
        PhaseName: Name of the phase (DelphiString31).
    
    Note:
        Prefer using pysq.dataclasses.PhaseResult for most use cases.
    """
    _fields_ = [
        ("WeightPC", c_double),
        ("ErrorOfFit", c_double),
        ("OrderNo", c_int),
        ("PhaseID", c_int),
        ("PhaseName", DelphiString31),
    ]


AResultRec = TResultRec * cmaxphases
PAResultRec = POINTER(AResultRec)


class TSetTraceRec(Structure):
    """
    ctypes structure for setting trace data.
    
    Used to specify trace (pattern) data when setting it programmatically.
    
    Attributes:
        Startangle: Starting angle in degrees 2θ (c_double).
        EndAngle: Ending angle in degrees 2θ (c_double).
        StepSize: Step size between measurements in degrees (c_double).
        wavelength: X-ray wavelength in Angstroms (c_double).
        NumberReadings: Number of data points (c_int).
        pTube: Pointer to tube information (c_void_p).
        pDate: Pointer to date information (c_void_p).
        pScanRate: Pointer to scan rate information (c_void_p).
        pComment: Pointer to comment string (c_void_p).
        charsize: Character size (c_int).
        ndecData: Number of decimal places for data (c_int).
        ndecAngles: Number of decimal places for angles (c_int).
        flags: Trace flags (c_long).
    """
    _fields_ = [
        ("Startangle", c_double),
        ("EndAngle", c_double),
        ("StepSize", c_double),
        ("wavelength", c_double),
        ("NumberReadings", c_int),
        ("pTube", c_void_p),
        ("pDate", c_void_p),
        ("pScanRate", c_void_p),
        ("pComment", c_void_p),
        ("charsize", c_int),
        ("ndecData", c_int),
        ("ndecAngles", c_int),
        ("flags", c_long),
    ]


ATrace = c_double * cmaxtracepoints
PATrace = POINTER(ATrace)


class TGetTraceRec(Structure):
    """
    ctypes structure for trace information.
    
    Returned when retrieving trace (pattern) data from a task.
    
    Attributes:
        Startangle: Starting angle in degrees 2θ (c_double).
        EndAngle: Ending angle in degrees 2θ (c_double).
        StepSize: Step size between measurements in degrees (c_double).
        NumberReadings: Number of data points (c_int).
        flags: Trace flags (c_long).
    
    Note:
        Prefer using pysq.dataclasses.TraceInfo for most use cases.
    """
    _fields_ = [
        ("Startangle", c_double),
        ("EndAngle", c_double),
        ("StepSize", c_double),
        ("NumberReadings", c_int),
        ("flags", c_long),
    ]


class TGlobalsRec(Structure):
    """
    ctypes structure for global refinement parameters.
    
    Contains global parameters that affect the entire refinement, such as
    instrument zero, asymmetry, background reference points, and equation type.
    
    Attributes:
        InstrumentZero: Instrument zero offset in degrees (c_double).
        Asymmetry: Asymmetry parameter (c_double).
        backref: Background reference points array, 14 elements (c_double * 14).
            Indices -1 to 12.
        equation: Equation type identifier (c_int).
    """
    _fields_ = [
        ("InstrumentZero", c_double),
        ("Asymmetry", c_double),
        ("backref", c_double * 14),  # -1..12 = 14 elements
        ("equation", c_int),
    ]


PGlobalsRec = POINTER(TGlobalsRec)


class TPhaseRefinablesRec(Structure):
    """
    ctypes structure for phase-specific refinable parameters.
    
    Contains all parameters that can be refined for a single phase during
    Rietveld refinement.
    
    Attributes:
        scales: Scale factor (c_double).
        unitcell: Unit cell parameters (TUnitCell).
        halfwidthes: Half-width parameters, array of 2 UVW (T12uvw).
        Pref: Preferred orientation parameter (c_double).
        Shape: Peak shape parameter (c_double).
        Amori: Amori parameter (c_double).
        extinction: Extinction parameter (c_double).
        temperature: Temperature factor (c_double).
        SplitShape: Split shape parameter (c_double).
        SplitRange: Split range parameters, array of 2 (TRealZeroOne).
        useSplitShape: Whether to use split shape (c_bool).
    """
    _fields_ = [
        ("scales", c_double),
        ("unitcell", TUnitCell),
        ("halfwidthes", T12uvw),
        ("Pref", c_double),
        ("Shape", c_double),
        ("Amori", c_double),
        ("extinction", c_double),
        ("temperature", c_double),
        ("SplitShape", c_double),
        ("SplitRange", TRealZeroOne),
        ("useSplitShape", c_bool),
    ]


APhaseRefinablesRec = TPhaseRefinablesRec * cmaxphases
PAPhaseRefinablesRec = POINTER(APhaseRefinablesRec)


class TCyrstalliteRec(Structure):
    """
    ctypes structure for crystallite size result.
    
    Contains the result of crystallite size analysis for a phase.
    
    Attributes:
        CrystalliteSize: Average crystallite size in nanometers (c_double).
        Error: Error estimate for crystallite size (c_double).
        OrderNo: Order number (c_int).
        PhaseID: Phase identifier (c_int).
        PhaseName: Name of the phase (DelphiString31).
    
    Note:
        Prefer using pysq.dataclasses.CrystalliteResult for most use cases.
    """
    _fields_ = [
        ("CrystalliteSize", c_double),
        ("Error", c_double),
        ("OrderNo", c_int),
        ("PhaseID", c_int),
        ("PhaseName", DelphiString31),
    ]


ACyrstalliteRec = TCyrstalliteRec * cmaxphases
PACyrstalliteRec = POINTER(ACyrstalliteRec)


class TAmorphous(Structure):
    """
    ctypes structure for amorphous content result.
    
    Contains the result of amorphous content analysis for a phase.
    
    Attributes:
        WeightPC: Weight percentage of amorphous content (c_double).
        Error: Error estimate for amorphous content (c_double).
        OrderNo: Order number (c_int).
        PhaseID: Phase identifier (c_int).
        PhaseName: Name of the phase (DelphiString31).
    
    Note:
        Prefer using pysq.dataclasses.AmorphousResult for most use cases.
    """
    _fields_ = [
        ("WeightPC", c_double),
        ("Error", c_double),
        ("OrderNo", c_int),
        ("PhaseID", c_int),
        ("PhaseName", DelphiString31),
    ]


AAmorphous = TAmorphous * (cmaxphases + 2)
PAAmorphous = POINTER(AAmorphous)

