namespace SHH.CameraSdk;

/// <summary>
/// 视频 SDK 统一异常类 (V3.3.1 修复版)
/// 核心职责：
/// <para>1. 封装标准化错误码、厂商原始错误码、设备品牌信息</para>
/// <para>2. 记录异常上下文快照，辅助故障定位与复盘</para>
/// 协作关系：
/// <para>1. 与 <see cref="HikErrorMapper"/> 配合：实现厂商错误码→标准错误码的转换</para>
/// <para>2. 与 <see cref="RecoveryPolicy"/> 配合：提供错误码输入，驱动故障自愈决策</para>
/// </summary>
public class CameraException : Exception
{
    #region --- 核心异常属性 (Core Exception Properties) ---

    /// <summary>
    /// 归一化后的标准错误码
    /// 业务用途：作为 RecoveryPolicy 的决策输入，屏蔽厂商差异
    /// </summary>
    public CameraErrorCode ErrorCode { get; }

    /// <summary>
    /// 厂商原始错误码（如海康 NET_DVR_GetLastError、大华 SDK 原生错误码）
    /// 业务用途：厂商文档对照、深度问题排查
    /// </summary>
    public int RawErrorCode { get; }

    /// <summary>
    /// 发生异常的设备品牌
    /// 业务用途：区分不同厂商的错误码规则，辅助错误映射
    /// </summary>
    public DeviceBrand Brand { get; }

    /// <summary>
    /// 异常发生时的上下文快照（只读集合，防止外部篡改）
    /// 存储内容：设备IP、通道号、操作参数、SDK句柄、时间戳等案发现场信息
    /// 业务用途：故障复盘时还原现场，快速定位根因
    /// </summary>
    public IReadOnlyDictionary<string, object> Context { get; init; } = new Dictionary<string, object>();

    #endregion

    #region --- 构造函数 (Constructors) ---

    /// <summary>
    /// 初始化 CameraException 实例
    /// </summary>
    /// <param name="errorCode">归一化标准错误码</param>
    /// <param name="message">异常描述信息</param>
    /// <param name="brand">设备品牌</param>
    /// <param name="rawErrorCode">厂商原始错误码（默认 0）</param>
    /// <param name="innerException">内部异常（默认 null）</param>
    public CameraException(
        CameraErrorCode errorCode,
        string message,
        DeviceBrand brand,
        int rawErrorCode = 0,
        Exception? innerException = null)
        : base(message, innerException)
    {
        ErrorCode = errorCode;
        Brand = brand;
        RawErrorCode = rawErrorCode;
        // 初始化上下文字典为可写的 Dictionary，兼容 WithContext 方法
        Context = new Dictionary<string, object>();
    }

    #endregion

    #region --- 工具方法 (Utility Methods) ---

    /// <summary>
    /// 链式添加上下文信息（Builder 模式）
    /// 业务用途：在抛出异常前，逐步追加案发现场信息
    /// </summary>
    /// <param name="key">上下文键（如 "DeviceIp", "ChannelIndex"）</param>
    /// <param name="value">上下文值</param>
    /// <returns>当前异常实例（支持链式调用）</returns>
    public CameraException WithContext(string key, object value)
    {
        // 强制转换为可写的 Dictionary，保证上下文可追加
        if (Context is Dictionary<string, object> contextDict)
        {
            contextDict[key] = value;
        }
        return this;
    }

    /// <summary>
    /// 重写 ToString 方法，输出标准化异常日志
    /// 格式：[CameraError] Brand: {品牌} | Code: {标准码}({原始码}) | Message: {描述} | Context: {上下文}
    /// </summary>
    /// <returns>格式化的异常字符串</returns>
    public override string ToString()
    {
        var contextStr = Context.Count > 0
            ? $" | Context: {string.Join(", ", Context.Select(kvp => $"{kvp.Key}={kvp.Value}"))}"
            : string.Empty;

        return $"[CameraError] Brand: {Brand} | Code: {ErrorCode}({RawErrorCode}) | Message: {Message}{contextStr}";
    }

    #endregion
}