#![allow(non_snake_case)]

/// Pointer to a UTF-16 string (wide char) terminated with `0`.
pub type PCWSTR = *const u16;
/// Mutable pointer to a UTF-16 buffer.
pub type PWSTR = *mut u16;
/// Pointer to an array of UTF-16 string pointers.
pub type PPWSTR = *mut PWSTR;
/// 32-bit boolean, mirrors the Win32 `BOOL` layout used by the C API.
pub type Bool32 = i32;

#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum OpenReturnCodes {
    Ok = 0,
    // --------- Application control and Connection ---------
    ErrorInternal = -1001,
    ErrorVcNotFound = -1002,
    ErrorCreateProcess = -1003,
    ErrorAlreadyRunning = -1004,
    ErrorCloseFailed = -1005,
    ErrorInstanceNotFound = -1006,
    ErrorInstanceBusy = -1007,
    ErrorNoConnection = -1008,
    ErrorVcNotReady = -1009,
    ErrorInvalidParameter = -1010,
    ErrorNoLicenseDeprecated = -1011,
    ErrorConnectionClosed = -1012,
    ErrorS7DosSimulationActive = -1013,
    ErrorVersionIncompatible = -1014,
    ErrorNotSupportedByBackend = -1015,
    WarningWindowEmbedding = 1002,
    WarningVersionClientOld = 1003,
    WarningVersionMiddlewareOld = 1004,
    WarningConnectionCorrupted = 1005,
    // --------- File handling (VCPs, startprofiles, etc.) ---------
    ErrorFileNotFound = -2001,
    ErrorProjectOpen = -2002,
    ErrorLoadFailed = -2003,
    ErrorNoProjectOpen = -2004,
    ErrorWriteProtected = -2005,
    ErrorSimRunning = -2006,
    ErrorWriteFailed = -2007,
    ErrorVcpCloseFailed = -2008,
    ErrorInvalidFile = -2009,
    ErrorCncSwUnavailable = -2010,
    ErrorFileCreationFailed = -2011,
    ErrorFrontendNotInstalled = -2012,
    ErrorFrontendNotLicensedDeprecated = -2013,
    ErrorFilePathTooLong = -2014,
    ErrorInvalidNckscaling = -2015,
    ErrorInvalidNcunumber = -2016,
    // --------- Simulation Control ---------
    ErrorStartSimFailed = -3001,
    ErrorStopSimFailed = -3002,
    ErrorResetSimFailed = -3004,
    ErrorSimSpeedInvalid = -3005,
    ErrorSimNotAvailable = -3006,
    ErrorSimNotRunning = -3007,
    SimRunning = 3001,
    SimNotRunning = 3002,
    // --------- Synchronized Operation ---------
    ErrorEventUnknown = -4001,
    ErrorNoEventsRegistered = -4002,
    ErrorSimInterrupted = -4003,
    // --------- Data Access ---------
    ErrorUnknownElement = -5001,
    ErrorInvalidDictId = -5002,
    ErrorInsufficientMemory = -5003,
    ErrorNoarray = -5004,
    ErrorWrongType = -5005,
    ErrorInsufficientRights = -5006,
    ErrorNotInWait = -5007,
    NoMoreData = 5001,
    // --------- File Operations ---------
    ErrorFileOpInvalidDomain = -6001,
    ErrorFileOpSourcePathNotAbsolute = -6002,
    ErrorFileOpSourceFileNotExists = -6003,
    ErrorFileOpDestinationPathNotAbsolute = -6004,
    ErrorFileOpDestinationAlreadyExists = -6005,
    ErrorFileOpDestinationDirectoryNotExists = -6006,
    ErrorFileOpDirectoryNotExists = -6007,
    ErrorFileOpDirectoryNotEmpty = -6008,
    ErrorFileSelectNotPossible = -6009,
    ErrorChannelNotExists = -6010,
    ErrorFileUsed = -6011,
    // --------- License handling ---------
    ErrorLicenseNoLicense = -7001,
    ErrorLicenseUnknownApplication = -7002,
    ErrorLicenseUnknownFrontend = -7003,
    ErrorLicenseNoConnection = -7004,
    ErrorLicenseNoLicenseHandler = -7005,
    ErrorLicenseErrorAtServerSite = -7006,
    ErrorLicenseOptionalLicenseKeyNotAvailable = -7007,
    ErrorLicenseOptionalLicenseKeyNotGranted = -7008,
    ErrorLicenseOptionalLicenseNotAqcuired = -7009,
    ErrorLicenseOptionalLicenseCheckFailed = -7010,
    ErrorLicenseKeyNotAvailable = -7011,
    ErrorLicenseKeyGrantFailed = -7012,
    ErrorLicenseKeyReleaseFailed = -7013,
    ErrorLicenseInvalid = -7014,
    ErrorLicenseAlreadyInUse = -7015,
    ErrorLicenseCheckFailed = -7016,
    ErrorLicenseAllLicensesInUse = -7017,
    ErrorLicenseUnknownLicense = -7018,
}

impl OpenReturnCodes {
    /// Convenience helper that mirrors the old `Ok` check in the C# wrapper.
    pub fn is_ok(self) -> bool {
        matches!(self, OpenReturnCodes::Ok)
    }
}

#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum OpenDictionaryElementType {
    Bool = 1,
    Integer8Bit = 2,
    UInteger8Bit = 3,
    Integer16Bit = 4,
    UInteger16Bit = 5,
    Integer32Bit = 6,
    UInteger32Bit = 7,
    Integer64Bit = 8,
    UInteger64Bit = 9,
    Double = 10,
    String = 11,
    IntegerArray32Bit = 12,
    UIntegerArray64Bit = 13,
    BoolArray = 14,
    DoubleArray = 15,
    StringArray = 16,
    UIntegerArray32Bit = 17,
    UIntegerArray16Bit = 18,
    UIntegerArray8Bit = 19,
}

#[repr(u64)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum OpenEventMaskDefinition {
    Unknown = 0x0000000000000000,
    NckFirstIpo = 0x0000000000000008,
    NckBootReady = 0x0000000000000004,
    NckIpo = 0x0000000000000001,
    NckChannelNewMotion = 0x0000000000000100,
    NckChannelNewBlock = 0x0000000000000200,
    NckChannelConfigChanged = 0x0000000000000400,
    NckChannelStartPositioningMotion = 0x0000000000000800,
    NckChannelEndPositioningMotion = 0x0000000000001000,
    NckChannelLengthSlicePath = 0x0000000000001001,
    NckChannelLengthSlicePositioning = 0x0000000000001002,
    NckChannelAngleSlicePositioning = 0x0000000000001003,
    NckChannelAngleSliceOrientation = 0x0000000000001004,
    NckChannelStateChanged = 0x0000000000001005,
    NckChannelProgramFinished = 0x0000000000001006,
    PlcOb1 = 0x0000000000010000,
    PlcHwConfigChanged = 0x0000000000020000,
    PlcAcyclicCommunication = 0x0000000000040000,
    ContentChanged = 0x0001000000000000,
    ResetStarted = 0x0002000000000000,
    ResetFinished = 0x0004000000000000,
}

#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum OpenAxisMode {
    None = 0,
    Interpolation = 1,
    Positioning = 2,
    SpeedLeft = 3,
    SpeedRight = 4,
    SpeedStop = 5,
    Following = 6,
}

#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum OpenAxisReferenceState {
    None = 0,
    NotReferenced = 1,
    Referenced = 2,
    ReferenceNotRequired = 3,
}

#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum OpenMotionType {
    None = 0,
    Rapid = 1,
    Linear = 2,
    Circle = 3,
    Spline = 4,
    Thread = 5,
    Involute = 6,
}

#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum OpenCircleDirection {
    None = 0,
    Cw = 1,
    Ccw = 2,
}

#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum OpenOperatingMode {
    None = 0,
    Auto = 1,
    Jog = 2,
    Mda = 3,
}

#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum OpenChannelState {
    None = 0,
    Activated = 1,
    Stopped = 2,
    Reseted = 3,
}

#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum OpenAxisType {
    None = 0,
    Linear = 1,
    Rotatory = 2,
    Modulo = 3,
    Spindle = 4,
}

#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum OpenProjectStates {
    Closed = 1,
    Opening = 2,
    Open = 3,
    Booting = 4,
    RunningOrPaused = 5,
    ShuttingDown = 6,
    Closing = 7,
    Resetting = 8,
    Saving = 9,
    Error = 10,
}

#[link(name = "open")]
extern "C" {
    #[link_name = "startApplication"]
    pub fn start_application(str_profile_file_name: PCWSTR) -> OpenReturnCodes;

    #[link_name = "stopApplication"]
    pub fn stop_application() -> OpenReturnCodes;

    #[link_name = "connect"]
    pub fn connect() -> OpenReturnCodes;

    #[link_name = "disconnect"]
    pub fn disconnect() -> OpenReturnCodes;

    #[link_name = "openProject"]
    pub fn open_project(str_file_name: PCWSTR) -> OpenReturnCodes;

    #[link_name = "createProject"]
    pub fn create_project(str_file_name: PCWSTR, str_version: PCWSTR) -> OpenReturnCodes;

    #[link_name = "createProjectWithScaling"]
    pub fn create_project_with_scaling(
        str_file_name: PCWSTR,
        str_version: PCWSTR,
        str_nck_scaling: PCWSTR
    ) -> OpenReturnCodes;

    #[link_name = "createProjectWithScalingNCUNumber"]
    pub fn create_project_with_scaling_ncu_number(
        str_file_name: PCWSTR,
        str_version: PCWSTR,
        str_nck_scaling: PCWSTR,
        ncu_number: u32
    ) -> OpenReturnCodes;

    #[link_name = "saveProject"]
    pub fn save_project() -> OpenReturnCodes;

    #[link_name = "closeProject"]
    pub fn close_project() -> OpenReturnCodes;

    #[link_name = "bootController"]
    pub fn boot_controller() -> OpenReturnCodes;

    #[link_name = "shutdownController"]
    pub fn shutdown_controller() -> OpenReturnCodes;

    #[link_name = "resetController"]
    pub fn reset_controller() -> OpenReturnCodes;

    #[link_name = "registerForEvents"]
    pub fn register_for_events(
        event_list_length: u32,
        event_list: *const OpenEventMaskDefinition
    ) -> OpenReturnCodes;

    #[link_name = "unregisterEvents"]
    pub fn unregister_events() -> OpenReturnCodes;

    #[link_name = "waitForEvents"]
    pub fn wait_for_events() -> OpenReturnCodes;

    #[link_name = "continueSimulation"]
    pub fn continue_simulation() -> OpenReturnCodes;

    #[link_name = "getDictionaryId"]
    pub fn get_dictionary_id(
        dictionary_element: PCWSTR,
        dictionary_id: *mut u32
    ) -> OpenReturnCodes;

    #[link_name = "registerWatch"]
    pub fn register_watch(
        watch_list_length: u32,
        dictionary_id_list: *const u32
    ) -> OpenReturnCodes;

    #[link_name = "unregisterWatch"]
    pub fn unregister_watch() -> OpenReturnCodes;

    #[link_name = "getDictionaryElementType"]
    pub fn get_dictionary_element_type(dictionary_id: u32, value: *mut u8) -> OpenReturnCodes;

    #[link_name = "readUnsignedInteger64BitArray"]
    pub fn read_unsigned_integer_64_bit_array(
        dictionary_id: u32,
        value_list_max_length: u32,
        value_list: *mut u64
    ) -> OpenReturnCodes;

    #[link_name = "readSignedInteger32BitArray"]
    pub fn read_signed_integer_32_bit_array(
        dictionary_id: u32,
        value_list_max_length: u32,
        value_list: *mut i32
    ) -> OpenReturnCodes;

    #[link_name = "readUnsignedInteger32BitArray"]
    pub fn read_unsigned_integer_32_bit_array(
        dictionary_id: u32,
        value_list_max_length: u32,
        value_list: *mut u32
    ) -> OpenReturnCodes;

    #[link_name = "readUnsignedInteger16BitArray"]
    pub fn read_unsigned_integer_16_bit_array(
        dictionary_id: u32,
        value_list_max_length: u32,
        value_list: *mut u16
    ) -> OpenReturnCodes;

    #[link_name = "readUnsignedInteger8BitArray"]
    pub fn read_unsigned_integer_8_bit_array(
        dictionary_id: u32,
        value_list_max_length: u32,
        value_list: *mut u8
    ) -> OpenReturnCodes;

    #[link_name = "readBoolArray"]
    pub fn read_bool_array(
        dictionary_id: u32,
        value_list_max_length: u32,
        value_list: *mut bool
    ) -> OpenReturnCodes;

    #[link_name = "readDoubleArray"]
    pub fn read_double_array(
        dictionary_id: u32,
        value_list_max_length: u32,
        value_list: *mut f64
    ) -> OpenReturnCodes;

    #[link_name = "readString"]
    pub fn read_string(
        dictionary_id: u32,
        string_max_length: u32,
        string_buffer: PWSTR
    ) -> OpenReturnCodes;

    #[link_name = "readStringArray"]
    pub fn read_string_array(
        dictionary_id: u32,
        string_array_max_length: u32,
        string_max_length: u32,
        string_array: PPWSTR
    ) -> OpenReturnCodes;

    #[link_name = "readUnsignedInteger16Bit"]
    pub fn read_unsigned_integer_16_bit(dictionary_id: u32, value: *mut u16) -> OpenReturnCodes;

    #[link_name = "readSignedInteger16Bit"]
    pub fn read_signed_integer_16_bit(dictionary_id: u32, value: *mut i16) -> OpenReturnCodes;

    #[link_name = "readUnsignedInteger32Bit"]
    pub fn read_unsigned_integer_32_bit(dictionary_id: u32, value: *mut u32) -> OpenReturnCodes;

    #[link_name = "readSignedInteger32Bit"]
    pub fn read_signed_integer_32_bit(dictionary_id: u32, value: *mut i32) -> OpenReturnCodes;

    #[link_name = "readUnsignedInteger64Bit"]
    pub fn read_unsigned_integer_64_bit(dictionary_id: u32, value: *mut u64) -> OpenReturnCodes;

    #[link_name = "readSignedInteger64Bit"]
    pub fn read_signed_integer_64_bit(dictionary_id: u32, value: *mut i64) -> OpenReturnCodes;

    #[link_name = "getNumArrayElements"]
    pub fn get_num_array_elements(
        dictionary_id: u32,
        num_array_elements: *mut u32
    ) -> OpenReturnCodes;

    #[link_name = "readBit"]
    pub fn read_bit(dictionary_id: u32, value: *mut Bool32) -> OpenReturnCodes;

    #[link_name = "readBool"]
    pub fn read_bool(dictionary_id: u32, value: *mut Bool32) -> OpenReturnCodes;

    #[link_name = "readByte"]
    pub fn read_byte(dictionary_id: u32, value: *mut u8) -> OpenReturnCodes;

    #[link_name = "readDouble"]
    pub fn read_double(dictionary_id: u32, value: *mut f64) -> OpenReturnCodes;

    #[link_name = "readWord"]
    pub fn read_word(dictionary_id: u32, value: *mut u16) -> OpenReturnCodes;

    #[link_name = "readDoubleWord"]
    pub fn read_double_word(dictionary_id: u32, value: *mut u32) -> OpenReturnCodes;

    #[link_name = "readLongWord"]
    pub fn read_long_word(dictionary_id: u32, value: *mut u64) -> OpenReturnCodes;

    #[link_name = "readNextEvent"]
    pub fn read_next_event(event: *mut u64) -> OpenReturnCodes;

    #[link_name = "readNextEventWithNcuIndex"]
    pub fn read_next_event_with_ncu_index(event: *mut u64, ncu_index: *mut i32) -> OpenReturnCodes;

    #[link_name = "writeBit"]
    pub fn write_bit(dictionary_id: u32, value: Bool32) -> OpenReturnCodes;

    #[link_name = "writeBool"]
    pub fn write_bool(dictionary_id: u32, value: Bool32) -> OpenReturnCodes;

    #[link_name = "writeByte"]
    pub fn write_byte(dictionary_id: u32, value: u8) -> OpenReturnCodes;

    #[link_name = "writeDouble"]
    pub fn write_double(dictionary_id: u32, value: f64) -> OpenReturnCodes;

    #[link_name = "writeWord"]
    pub fn write_word(dictionary_id: u32, value: u16) -> OpenReturnCodes;

    #[link_name = "writeDoubleWord"]
    pub fn write_double_word(dictionary_id: u32, value: u32) -> OpenReturnCodes;

    #[link_name = "writeLongWord"]
    pub fn write_long_word(dictionary_id: u32, value: u64) -> OpenReturnCodes;

    #[link_name = "writeBoolArray"]
    pub fn write_bool_array(
        dictionary_id: u32,
        value_list_length: u32,
        value_list: *const bool
    ) -> OpenReturnCodes;

    #[link_name = "getSimulationSpeed"]
    pub fn get_simulation_speed(percent: *mut u32) -> OpenReturnCodes;

    #[link_name = "setSimulationSpeed"]
    pub fn set_simulation_speed(percent: u32) -> OpenReturnCodes;

    #[link_name = "getCardPath"]
    pub fn get_card_path(card_path_max_length: u32, card_path: PWSTR) -> OpenReturnCodes;

    #[link_name = "getCardPaths"]
    pub fn get_card_paths(
        card_paths_array_max_length: u32,
        card_path_max_length: u32,
        card_paths: PPWSTR
    ) -> OpenReturnCodes;

    #[link_name = "getFile"]
    pub fn get_file(source_file_path: PCWSTR, destination_file_path: PCWSTR) -> OpenReturnCodes;

    #[link_name = "putFile"]
    pub fn put_file(source_file_path: PCWSTR, destination_file_path: PCWSTR) -> OpenReturnCodes;

    #[link_name = "selectFile"]
    pub fn select_file(source_file_path: PCWSTR, channel_name: PCWSTR) -> OpenReturnCodes;

    #[link_name = "deleteFile"]
    pub fn delete_file(file_path: PCWSTR) -> OpenReturnCodes;

    #[link_name = "deleteDirectory"]
    pub fn delete_directory(directory_path: PCWSTR) -> OpenReturnCodes;

    #[link_name = "createDirectory"]
    pub fn create_directory(directory_path: PCWSTR) -> OpenReturnCodes;

    #[link_name = "listDirectory"]
    pub fn list_directory(directory_path: PCWSTR, result_file_path: PCWSTR) -> OpenReturnCodes;

    #[link_name = "getVersionInformation"]
    pub fn get_version_information(destination_file_path: PCWSTR) -> OpenReturnCodes;

    #[link_name = "getProjectInformation"]
    pub fn get_project_information(
        vcp_file_path: PCWSTR,
        destination_file_path: PCWSTR
    ) -> OpenReturnCodes;

    #[link_name = "getCurrentProjectInformation"]
    pub fn get_current_project_information(destination_file_path: PCWSTR) -> OpenReturnCodes;

    #[link_name = "getCurrentProjectState"]
    pub fn get_current_project_state(project_state: *mut OpenProjectStates) -> OpenReturnCodes;

    #[link_name = "importProjectSettings"]
    pub fn import_project_settings(
        file_name: PCWSTR,
        import_content_file_name: PCWSTR
    ) -> OpenReturnCodes;

    #[link_name = "exportProjectSettings"]
    pub fn export_project_settings(file_name: PCWSTR) -> OpenReturnCodes;

    #[link_name = "writeUnsignedInteger8BitArray"]
    pub fn write_unsigned_integer_8_bit_array(
        dictionary_id: u32,
        value_list_max_length: u32,
        value_list: *const u8
    ) -> OpenReturnCodes;

    #[link_name = "getNumberOfNCUs"]
    pub fn get_number_of_ncus(number_of_ncus: *mut u32) -> OpenReturnCodes;
}
