"""Pythonic dataclasses that wrap ctypes structures."""

from dataclasses import dataclass
from typing import List, TYPE_CHECKING

from .types import (
    TUnitCell, Tuvw, TOpenTaskRec, TLoadPatternRec, TStartRefinementRec,
    TSearchMatchRec, TReportRec, TResultRec, TGetTraceRec,
    TCyrstalliteRec, TAmorphous
)

if TYPE_CHECKING:
    from .types import AResultRec


@dataclass(frozen=False)
class UnitCell:
    """Unit cell parameters for a crystal phase.
    
    Attributes:
        a: Unit cell edge length a in Angstroms.
        b: Unit cell edge length b in Angstroms.
        c: Unit cell edge length c in Angstroms.
        alpha: Angle between b and c axes in degrees.
        beta: Angle between a and c axes in degrees.
        gamma: Angle between a and b axes in degrees.
    """
    a: float
    b: float
    c: float
    alpha: float
    beta: float
    gamma: float
    
    @classmethod
    def from_ctypes(cls, tunit_cell: TUnitCell) -> 'UnitCell':
        """Create UnitCell from ctypes TUnitCell structure."""
        return cls(
            a=tunit_cell.A, b=tunit_cell.B, c=tunit_cell.C,
            alpha=tunit_cell.alpha, beta=tunit_cell.beta, gamma=tunit_cell.gamma
        )
    
    def to_ctypes(self) -> TUnitCell:
        """Convert UnitCell to ctypes TUnitCell structure."""
        cell = TUnitCell()
        cell.A, cell.B, cell.C = self.a, self.b, self.c
        cell.alpha, cell.beta, cell.gamma = self.alpha, self.beta, self.gamma
        return cell


@dataclass(frozen=False)
class UVW:
    """UVW (Caglioti) parameters for peak profile fitting.
    
    Attributes:
        u: U parameter (constant term).
        v: V parameter (linear term).
        w: W parameter (quadratic term).
    """
    u: float
    v: float
    w: float
    
    @classmethod
    def from_ctypes(cls, tuvw: Tuvw) -> 'UVW':
        """Create UVW from ctypes Tuvw structure."""
        return cls(u=tuvw.u, v=tuvw.v, w=tuvw.w)
    
    def to_ctypes(self) -> Tuvw:
        """Convert UVW to ctypes Tuvw structure."""
        uvw = Tuvw()
        uvw.u, uvw.v, uvw.w = self.u, self.v, self.w
        return uvw


@dataclass(frozen=False)
class TaskInfo:
    """Information about an opened Siroquant task.
    
    Attributes:
        job_handle: Unique handle for this task.
        number_phases: Number of phases defined in the task.
        number_points: Number of data points in the task.
        flags: Task flags.
        return_code: Return code from opening the task.
    """
    job_handle: int
    number_phases: int
    number_points: int
    flags: int
    return_code: int
    
    @classmethod
    def from_ctypes(cls, job_handle: int, open_rec: TOpenTaskRec) -> 'TaskInfo':
        """Create TaskInfo from ctypes TOpenTaskRec structure."""
        return cls(
            job_handle=job_handle,
            number_phases=open_rec.numberPhases,
            number_points=open_rec.Numberpoints,
            flags=open_rec.flags,
            return_code=open_rec.return_val
        )
    
    def __repr__(self) -> str:
        return f"TaskInfo(handle={self.job_handle}, phases={self.number_phases}, points={self.number_points})"


@dataclass(frozen=False)
class PatternInfo:
    """Information about a loaded X-ray diffraction pattern.
    
    Attributes:
        pattern_type: Type identifier for the pattern format.
        pattern_no: Pattern number assigned by the system.
        number_points: Number of data points in the loaded pattern.
        flags: Pattern flags.
        return_code: Return code from loading the pattern.
    """
    pattern_type: int
    pattern_no: int
    number_points: int
    flags: int
    return_code: int
    
    @classmethod
    def from_ctypes(cls, load_rec: TLoadPatternRec) -> 'PatternInfo':
        """Create PatternInfo from ctypes TLoadPatternRec structure."""
        return cls(
            pattern_type=load_rec.patterntype,
            pattern_no=load_rec.patternNo,
            number_points=load_rec.Numberpoints,
            flags=load_rec.flags,
            return_code=load_rec.return_val
        )
    
    def __repr__(self) -> str:
        return f"PatternInfo(type={self.pattern_type}, no={self.pattern_no}, points={self.number_points})"


@dataclass(frozen=False)
class RefinementParams:
    """Parameters for quantitative phase analysis refinement.
    
    Attributes:
        n_auto_prescale: Number of automatic prescaling iterations.
        n_refs: Number of refinement iterations.
        cutoff: Cutoff value for refinement.
        error_cutoff: Error cutoff value.
        error_pc: Error percentage threshold.
        flags: Refinement flags.
        ret_flags: Return flags set by the refinement process.
    """
    n_auto_prescale: int
    n_refs: int
    cutoff: float
    error_cutoff: float
    error_pc: float
    flags: int
    ret_flags: int = 0
    
    def to_ctypes(self) -> TStartRefinementRec:
        """Convert RefinementParams to ctypes TStartRefinementRec structure."""
        rec = TStartRefinementRec()
        rec.nAutoPrescale = self.n_auto_prescale
        rec.nRefs = self.n_refs
        rec.cutoff = self.cutoff
        rec.ErrorCutoff = self.error_cutoff
        rec.ErrorPC = self.error_pc
        rec.flags = self.flags
        rec.RetFlags = self.ret_flags
        return rec


@dataclass(frozen=False)
class PhaseResult:
    """Quantitative phase analysis result for a single phase.
    
    Attributes:
        phase_id: Unique identifier for this phase.
        phase_name: Name of the phase.
        weight_pc: Weight percentage of this phase.
        error_of_fit: Error of fit for this phase.
        order_no: Order number.
    """
    phase_id: int
    phase_name: str
    weight_pc: float
    error_of_fit: float
    order_no: int = 0
    
    @classmethod
    def from_ctypes(cls, result_rec: TResultRec) -> 'PhaseResult':
        """Create PhaseResult from ctypes TResultRec structure."""
        return cls(
            phase_id=result_rec.PhaseID,
            phase_name=str(result_rec.PhaseName),
            weight_pc=result_rec.WeightPC,
            error_of_fit=result_rec.ErrorOfFit,
            order_no=result_rec.OrderNo
        )
    
    def __repr__(self) -> str:
        return f"PhaseResult({self.phase_name!r}, {self.weight_pc:.2f}%)"


@dataclass(frozen=False)
class RefinementResult:
    """Complete results from a quantitative phase analysis refinement.
    
    Attributes:
        chi_squared: Chi-squared value of the overall fit.
        r_factor: R-factor of the fit.
        n_phases: Number of phases identified.
        phases: List of PhaseResult objects.
        flags: Result flags.
    """
    chi_squared: float
    r_factor: float
    n_phases: int
    phases: List[PhaseResult]
    flags: int
    
    @classmethod
    def from_ctypes(cls, report_rec: TReportRec, phases_array: 'AResultRec', n_phases: int) -> 'RefinementResult':
        """Create RefinementResult from ctypes structures."""
        phases = [PhaseResult.from_ctypes(phases_array[i]) for i in range(n_phases)]
        return cls(
            chi_squared=report_rec.ChiSQ,
            r_factor=report_rec.Rfactor,
            n_phases=report_rec.nPhases,
            phases=phases,
            flags=report_rec.flags
        )
    
    def __repr__(self) -> str:
        return f"RefinementResult(χ²={self.chi_squared:.4f}, R={self.r_factor:.4f}, phases={self.n_phases})"


@dataclass(frozen=False)
class SearchMatchResult:
    """Result from a phase search/match operation.
    
    Attributes:
        phase_id: Unique identifier for this phase.
        phase_name: Name of the phase.
        status: Status string.
        weight_pc: Estimated weight percentage.
        error_of_fit: Error of fit for this phase match.
    """
    phase_id: int
    phase_name: str
    status: str
    weight_pc: float
    error_of_fit: float
    
    @classmethod
    def from_ctypes(cls, match_rec: TSearchMatchRec) -> 'SearchMatchResult':
        """Create SearchMatchResult from ctypes TSearchMatchRec structure."""
        return cls(
            phase_id=match_rec.PhaseID,
            phase_name=str(match_rec.PhaseName),
            status=str(match_rec.Status),
            weight_pc=match_rec.WeightPC,
            error_of_fit=match_rec.ErrorOfFit
        )


@dataclass(frozen=False)
class TraceInfo:
    """Information about X-ray diffraction trace data.
    
    Attributes:
        start_angle: Starting angle in degrees (2θ).
        end_angle: Ending angle in degrees (2θ).
        step_size: Step size between measurements in degrees.
        number_readings: Number of data points.
        flags: Trace flags.
    """
    start_angle: float
    end_angle: float
    step_size: float
    number_readings: int
    flags: int
    
    @classmethod
    def from_ctypes(cls, trace_rec: TGetTraceRec) -> 'TraceInfo':
        """Create TraceInfo from ctypes TGetTraceRec structure."""
        return cls(
            start_angle=trace_rec.Startangle,
            end_angle=trace_rec.EndAngle,
            step_size=trace_rec.StepSize,
            number_readings=trace_rec.NumberReadings,
            flags=trace_rec.flags
        )
    
    def __repr__(self) -> str:
        return f"TraceInfo({self.start_angle:.2f}°-{self.end_angle:.2f}°, {self.number_readings} pts)"


@dataclass(frozen=False)
class CrystalliteResult:
    """Crystallite size analysis result for a phase.
    
    Attributes:
        crystallite_size: Average crystallite size in nanometers.
        error: Error estimate for the crystallite size.
        order_no: Order number.
        phase_id: Unique identifier for this phase.
        phase_name: Name of the phase.
    """
    crystallite_size: float
    error: float
    order_no: int
    phase_id: int
    phase_name: str
    
    @classmethod
    def from_ctypes(cls, cryst_rec: TCyrstalliteRec) -> 'CrystalliteResult':
        """Create CrystalliteResult from ctypes TCyrstalliteRec structure."""
        return cls(
            crystallite_size=cryst_rec.CrystalliteSize,
            error=cryst_rec.Error,
            order_no=cryst_rec.OrderNo,
            phase_id=cryst_rec.PhaseID,
            phase_name=str(cryst_rec.PhaseName)
        )
    
    def __repr__(self) -> str:
        return f"CrystalliteResult({self.phase_name!r}, {self.crystallite_size:.2f}nm)"


@dataclass(frozen=False)
class AmorphousResult:
    """Amorphous content analysis result for a phase.
    
    Attributes:
        weight_pc: Weight percentage of amorphous content.
        error: Error estimate.
        order_no: Order number.
        phase_id: Unique identifier for this phase.
        phase_name: Name of the phase.
    """
    weight_pc: float
    error: float
    order_no: int
    phase_id: int
    phase_name: str
    
    @classmethod
    def from_ctypes(cls, amorph_rec: TAmorphous) -> 'AmorphousResult':
        """Create AmorphousResult from ctypes TAmorphous structure."""
        return cls(
            weight_pc=amorph_rec.WeightPC,
            error=amorph_rec.Error,
            order_no=amorph_rec.OrderNo,
            phase_id=amorph_rec.PhaseID,
            phase_name=str(amorph_rec.PhaseName)
        )
    
    def __repr__(self) -> str:
        return f"AmorphousResult({self.phase_name!r}, {self.weight_pc:.2f}%)"
