"""
Constants and error codes for the SQ API.

This module defines constants used throughout the SQ API, including:
- Array size limits (cmaxphases, cmaxtracepoints)
- DLL name (LIB_NAME)
- Error codes (SQErrorCode class)
- Error messages mapping (ERROR_MESSAGES)

Example:
    >>> from pysq.constants import SQErrorCode, ERROR_MESSAGES
    >>> 
    >>> # Check error code
    >>> if result == SQErrorCode.OK:
    ...     print("Operation succeeded")
    >>> elif result == SQErrorCode.TASK_OPEN_FAILURE:
    ...     print(ERROR_MESSAGES[SQErrorCode.TASK_OPEN_FAILURE])
"""

# Constants
cmaxphases = 100
"""Maximum number of phases supported in a single task."""

cmaxtracepoints = 1000000
"""Maximum number of trace (pattern) data points supported."""

LIB_NAME = 'sq_api.dll'
"""Default name of the SQ API DLL file."""

# Error code constants
class SQErrorCode:
    """
    Error codes from the SQ API.
    
    This class contains all error codes returned by the SQ API DLL functions.
    Positive values (0, 1) typically indicate success or status, while
    negative values indicate errors.
    
    Attributes:
        OK: Operation successful (0).
        INITIALIZED: API already initialized (1).
        TASK_COMPLETED: Refinement task completed (1).
        TASK_REFINING: Refinement still in progress (-16).
        TASK_NOT_STARTED: Task has not been started (-1).
        FINALIZATION_FAILURE: Failed to finalize API (-1).
        CLOSE_FAILURE: Failed to close task (-2).
        INVALID_TASK: Invalid task handle (-3).
        NIL_TASK: Task handle is nil/null (-4).
        ACTIVE_TASK: Task is still active (-5).
        TASK_OPEN_FAILURE: Failed to open task file (-6).
        REFINEMENT_FAILED: Refinement failed (-7).
        ILLEGAL_FLAG_VALUE: Illegal flag value (-8).
        INSUFFICIENT_PATTERNS: Insufficient pattern data (-9).
        ILLEGAL_CHAR_SIZE: Illegal character size (-10).
        NO_CAL_DATA: No calibration data available (-11).
        NO_BACK_SUB_DATA: No background subtraction data (-12).
        DONGL_FAILURE: DLL operation failure (-13).
        NO_TRACE: No trace data available (-14).
        SAVE_FAILED: Failed to save task (-15).
        NO_LIBRARY: Library directory not set (-16).
        NO_LINE_WIDTH: No line width data available (-17).
        UVW_ERROR: UVW parameter error (-18).
        BAD_SPIKE: Bad spike detected (-19).
        AMORPH_RESULT_ARRAY_TOO_SMALL: Amorphous result array too small (-20).
        BACKGROUND_REFINEMENT_ERROR: Background refinement error (-21).
        UNKNOWN_EXCEPTION: Unknown exception occurred (-666).
    
    Example:
        >>> from pysq.constants import SQErrorCode
        >>> 
        >>> result = api.initialize()
        >>> if result == SQErrorCode.OK:
        ...     print("Initialized successfully")
        >>> elif result == SQErrorCode.INITIALIZED:
        ...     print("Already initialized")
        >>> else:
        ...     print(f"Error code: {result}")
    """
    OK = 0
    """Operation successful."""
    INITIALIZED = 1
    """API already initialized."""
    TASK_COMPLETED = 1
    """Refinement task completed successfully."""
    TASK_REFINING = -16  # Still refining (matches Delphi csqAPItaskRefining)
    """Refinement still in progress."""
    TASK_NOT_STARTED = -1
    """Task has not been started."""
    FINALIZATION_FAILURE = -1
    """Failed to finalize API."""
    CLOSE_FAILURE = -2
    """Failed to close task."""
    INVALID_TASK = -3
    """Invalid task handle."""
    NIL_TASK = -4
    """Task handle is nil/null."""
    ACTIVE_TASK = -5
    """Task is still active."""
    TASK_OPEN_FAILURE = -6
    """Failed to open task file."""
    REFINEMENT_FAILED = -7
    """Refinement failed."""
    ILLEGAL_FLAG_VALUE = -8
    """Illegal flag value."""
    INSUFFICIENT_PATTERNS = -9
    """Insufficient pattern data."""
    ILLEGAL_CHAR_SIZE = -10
    """Illegal character size."""
    NO_CAL_DATA = -11
    """No calibration data available."""
    NO_BACK_SUB_DATA = -12
    """No background subtraction data available."""
    DONGL_FAILURE = -13
    """DLL operation failure."""
    NO_TRACE = -14
    """No trace data available."""
    SAVE_FAILED = -15
    """Failed to save task."""
    NO_LIBRARY = -16
    """Library directory not set or invalid."""
    NO_LINE_WIDTH = -17
    """No line width data available."""
    UVW_ERROR = -18
    """UVW parameter error."""
    BAD_SPIKE = -19
    """Bad spike detected."""
    AMORPH_RESULT_ARRAY_TOO_SMALL = -20
    """Amorphous result array too small."""
    BACKGROUND_REFINEMENT_ERROR = -21
    """Background refinement error."""
    UNKNOWN_EXCEPTION = -666
    """Unknown exception occurred."""

# Error messages mapping
# Mapping of error codes to human-readable error messages.
# This dictionary maps SQErrorCode constants to descriptive error messages
# that help users understand what went wrong. Used by format_error_message()
# to create user-friendly error messages.
# Keys are SQErrorCode constants (integers), values are error message strings.
class SaveTaskFlags:
    """Flags for the save_task() method (bitfield, combinable with |).

    Corresponds to Delphi constants ``csqAPIsavetask*`` in ``SQapiDef.pas``.

    Attributes:
        DEFAULT: No special options (0). Saves as the task's current format,
            overwriting the original file.
        ENFORCE_DIRECTORIES: Create intermediate directories in the destination
            path if they do not already exist (1).
        TRACSCAL: Include TRACSCAL refinement data in the saved file (2).
        NO_RENAME: Do not rename the task's internal filename to the new path;
            keep the original internal filename (4).
        AS_TMK: Force save in ``.tmk`` (template) format regardless of the
            supplied filename extension (8).
        AS_TSK: Force save in ``.tsk`` (task) format regardless of the
            supplied filename extension (16).

    Example:
        >>> from pysq import SQAPI, SaveTaskFlags
        >>> api = SQAPI()
        >>> api.initialize()
        >>> task_info = api.open_task("sample.tsk")
        >>> api.refine(task_info.job_handle)
        >>> # Save with results, creating any missing directories
        >>> api.save_task(task_info.job_handle, r"output\\result.tsk",
        ...               SaveTaskFlags.ENFORCE_DIRECTORIES)
        >>> # Save as a template file
        >>> api.save_task(task_info.job_handle, "template.tmk",
        ...               SaveTaskFlags.AS_TMK)
    """
    DEFAULT = 0
    """No special save options."""
    ENFORCE_DIRECTORIES = 1
    """Create intermediate output directories if they do not exist."""
    TRACSCAL = 2
    """Include TRACSCAL (refinement engine) data in the saved file."""
    NO_RENAME = 4
    """Keep the task's original internal filename instead of updating it."""
    AS_TMK = 8
    """Force save as a .tmk template file."""
    AS_TSK = 16
    """Force save as a .tsk task file."""


class ReportResultsFlags:
    """Flags for the report_results() / refine() methods (bitfield, combinable with |).

    Corresponds to the Delphi ``cSQapi*`` constants used to set
    ``TReportRec.flags`` before calling ``SQ4ReportResults`` /
    ``SQ4ReportResultsFull``.

    Result set selection
    --------------------
    UNCORRECTED : int
        Return the raw (uncorrected) weight percentages (default, 0).
    CORRECTED : int
        Return the TRACSCAL-corrected weight percentages (16 = cSQapiCorrectedResults).

    Sorting
    -------
    SORT_ID : int
        Sort phases by phase ID ascending (1 = cSQapiSortId).
    SORT_NAME : int
        Sort phases by phase name ascending (3 = cSQapiSortName).
    SORT_RESULT : int
        Sort phases by weight % descending (5 = cSQapiSortResult).
    SORT_ERROR : int
        Sort phases by error % descending (7 = cSQapiSortError).
    INVERSE_SORT : int
        Reverse the selected sort order (8 = cSQapiInverseSort).

    Example::

        from pysq import ReportResultsFlags
        results = api.refine(handle, report_flags=ReportResultsFlags.CORRECTED)
        results = api.refine(
            handle,
            report_flags=ReportResultsFlags.CORRECTED | ReportResultsFlags.SORT_RESULT,
        )
    """
    UNCORRECTED  = 0   # cSQapiUncorrectedResults
    CORRECTED    = 16  # cSQapiCorrectedResults
    SORT_ID      = 1   # cSQapiSortId
    SORT_NAME    = 3   # cSQapiSortName
    SORT_RESULT  = 5   # cSQapiSortResult
    SORT_ERROR   = 7   # cSQapiSortError
    INVERSE_SORT = 8   # cSQapiInverseSort


ERROR_MESSAGES = {
    SQErrorCode.TASK_OPEN_FAILURE: "Failed to open task file. Check file path and permissions.",
    SQErrorCode.REFINEMENT_FAILED: "Refinement failed. Check pattern data and parameters.",
    # Note: -16 is used for both TASK_REFINING and NO_LIBRARY in Delphi code
    # In check_refinement context, -16 means TASK_REFINING (refinement in progress)
    # NO_LIBRARY error would come from other functions, not check_refinement
    SQErrorCode.NO_LIBRARY: "Library directory not set or invalid. Use set_lib_dir() first.",
    SQErrorCode.TASK_NOT_STARTED: "Operation failed or task has not been started (Error -1).",
    SQErrorCode.INVALID_TASK: "Invalid task handle.",
    SQErrorCode.NIL_TASK: "Task handle is nil/null.",
    SQErrorCode.ACTIVE_TASK: "Task is still active.",
    SQErrorCode.CLOSE_FAILURE: "Failed to close task.",
    # Note: FINALIZATION_FAILURE also uses code -1, but is handled specifically
    # in SQAPI.initialize() with a custom message.
    # We use the generic message above for other contexts.
    SQErrorCode.NO_TRACE: "No trace data available.",
    SQErrorCode.SAVE_FAILED: "Failed to save task.",
    SQErrorCode.NO_LINE_WIDTH: "No line width data available.",
    SQErrorCode.UVW_ERROR: "UVW parameter error.",
    SQErrorCode.BAD_SPIKE: "Bad spike detected.",
    SQErrorCode.INSUFFICIENT_PATTERNS: "Insufficient pattern data.",
    SQErrorCode.ILLEGAL_FLAG_VALUE: "Illegal flag value.",
    SQErrorCode.ILLEGAL_CHAR_SIZE: "Illegal character size.",
    SQErrorCode.NO_CAL_DATA: "No calibration data available.",
    SQErrorCode.NO_BACK_SUB_DATA: "No background subtraction data available.",
    SQErrorCode.DONGL_FAILURE: (
        "Dongle initialization failed. Possible causes:\n"
        "  - Hardware dongle not connected or not found\n"
        "  - Dongle has expired (date or counter expired)\n"
        "  - Invalid dongle feature version (V5 Premium requires version 3)\n"
        "  - Invalid license set on dongle\n"
        "  - System time is incorrect (illegal time of day)\n"
        "  - Dongle driver not installed or not working properly\n"
        "Please check that the WIBU-KEY dongle is properly connected and has valid licenses."
    ),
    SQErrorCode.AMORPH_RESULT_ARRAY_TOO_SMALL: "Amorphous result array too small.",
    SQErrorCode.BACKGROUND_REFINEMENT_ERROR: "Background refinement error.",
    SQErrorCode.UNKNOWN_EXCEPTION: (
        "An unknown exception occurred during API operation. "
        "This may indicate an internal error in the DLL. "
        "Check the application logs for more details."
    ),
}

