// Copyright 2026 California Institute of Technology
//
// You should have received a copy of the licensing terms for this
// software included in the file “LICENSE” located in the top-level
// directory of this package. If you did not, you can view a copy at
// http://dcc.ligo.org/M1500244/LICENSE.txt

use std::ffi::CStr;
use std::os::raw::{c_int, c_long};
use thiserror::Error;

pub type EpicsResult<T> = Result<T, EpicsError>;
#[derive(Error, Debug, Clone)]
pub enum EpicsError {
    #[error("General error {0}")]
    General(String),
    #[error("Epics error {0}:{1}")]
    Error(c_int, String),
    #[error("This channel is already subscribed")]
    MultipleSubscriptions,
}

impl From<c_int> for EpicsError {
    fn from(value: c_int) -> Self {
        // SAFETY: ca_message returns a pointer into a static message table
        // (or NULL, which we check); it is never freed, so borrowing it via
        // CStr for the duration of the copy is sound.
        let msg: String = unsafe {
            let ptr = epics_rs_sys::ca_message(value as c_long);
            if ptr.is_null() {
                "Unknown".to_string()
            } else {
                let cmsg = CStr::from_ptr(ptr);
                match cmsg.to_str() {
                    Ok(s) => s.to_owned(),
                    Err(_) => "Unknown".to_string(),
                }
            }
        };
        Self::Error(value, msg)
    }
}
