//! # Comprehensive error types and handling
//!
//! This module implements the KIP Standard Error Codes as defined in KIP specification Appendix 4.
//! Error codes are divided into 4 categories:
//! - **1xxx (Syntax Errors)**: Syntax errors where the code generated by the LLM has incorrect format.
//! - **2xxx (Schema Errors)**: Schema errors violating type definitions or data constraints.
//! - **3xxx (Logic/Data Errors)**: Logic or data errors, such as referencing non-existent variables or IDs.
//! - **4xxx (System Errors)**: System-level errors, such as timeouts or insufficient permissions.

use nom_language::error::{VerboseError, VerboseErrorKind, convert_error};
use std::fmt::Display;

use thiserror::Error;

/// KIP Standard Error Codes
///
/// These codes follow the KIP specification for standardized error reporting.
/// Error codes enable AI Agents to implement self-correction capabilities.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KipErrorCode {
    // 1xxx: Syntax & Parsing errors
    /// KIP_1001: InvalidSyntax - KQL/KML code cannot be parsed due to spelling or structural errors.
    InvalidSyntax,
    /// KIP_1002: InvalidIdentifier - Used illegal identifier format (e.g., starting with a number).
    InvalidIdentifier,
    /// KIP_1003: UnsupportedVersion - The requested protocol version is not supported.
    UnsupportedVersion,

    // 2xxx: Schema & Type errors
    /// KIP_2001: TypeMismatch - Attempted to use a Concept Type or Proposition Predicate undefined in Schema.
    TypeMismatch,
    /// KIP_2002: AttributeUndefined - Attempted to write an undefined attribute (if Schema is in strict mode).
    AttributeUndefined,
    /// KIP_2003: ConstraintViolation - Violated data constraints (e.g., missing required field).
    ConstraintViolation,
    /// KIP_2004: InvalidValueType - JSON type of attribute value mismatches Schema definition.
    InvalidValueType,

    // 3xxx: Logic & Data errors
    /// KIP_3001: ReferenceError - Referenced an undefined variable or Handle.
    ReferenceError,
    /// KIP_3002: NotFound - Node/Link with specified ID or name does not exist.
    NotFound,
    /// KIP_3003: DuplicateExists - Violated uniqueness constraint.
    DuplicateExists,
    /// KIP_3004: ImmutableTarget - Attempted to modify/delete protected system nodes.
    ImmutableTarget,

    // 4xxx: System & Execution errors
    /// KIP_4001: ExecutionTimeout - Query too complex, execution time exceeded system limit.
    ExecutionTimeout,
    /// KIP_4002: ResourceExhausted - Result set too large or insufficient memory.
    ResourceExhausted,
    /// KIP_4003: InternalError - Unknown internal database error.
    InternalError,
}

impl KipErrorCode {
    /// Returns the string code (e.g., "KIP_1001")
    pub fn code(&self) -> &'static str {
        match self {
            // 1xxx: Syntax & Parsing
            Self::InvalidSyntax => "KIP_1001",
            Self::InvalidIdentifier => "KIP_1002",
            Self::UnsupportedVersion => "KIP_1003",
            // 2xxx: Schema & Type
            Self::TypeMismatch => "KIP_2001",
            Self::AttributeUndefined => "KIP_2002",
            Self::ConstraintViolation => "KIP_2003",
            Self::InvalidValueType => "KIP_2004",
            // 3xxx: Logic & Data
            Self::ReferenceError => "KIP_3001",
            Self::NotFound => "KIP_3002",
            Self::DuplicateExists => "KIP_3003",
            Self::ImmutableTarget => "KIP_3004",
            // 4xxx: System & Execution
            Self::ExecutionTimeout => "KIP_4001",
            Self::ResourceExhausted => "KIP_4002",
            Self::InternalError => "KIP_4003",
        }
    }

    /// Returns the error name (e.g., "InvalidSyntax")
    pub fn name(&self) -> &'static str {
        match self {
            // 1xxx: Syntax & Parsing
            Self::InvalidSyntax => "InvalidSyntax",
            Self::InvalidIdentifier => "InvalidIdentifier",
            Self::UnsupportedVersion => "UnsupportedVersion",
            // 2xxx: Schema & Type
            Self::TypeMismatch => "TypeMismatch",
            Self::AttributeUndefined => "AttributeUndefined",
            Self::ConstraintViolation => "ConstraintViolation",
            Self::InvalidValueType => "InvalidValueType",
            // 3xxx: Logic & Data
            Self::ReferenceError => "ReferenceError",
            Self::NotFound => "NotFound",
            Self::DuplicateExists => "DuplicateExists",
            Self::ImmutableTarget => "ImmutableTarget",
            // 4xxx: System & Execution
            Self::ExecutionTimeout => "ExecutionTimeout",
            Self::ResourceExhausted => "ResourceExhausted",
            Self::InternalError => "InternalError",
        }
    }

    /// Returns a recovery hint for the AI Agent
    pub fn hint(&self) -> &'static str {
        match self {
            // 1xxx: Syntax & Parsing
            Self::InvalidSyntax => {
                "Check parenthesis matching, keyword spelling, and statement structure. Ensure JSON data format is valid."
            }
            Self::InvalidIdentifier => "Identifiers must match regex `[a-zA-Z_][a-zA-Z0-9_]*`.",
            Self::UnsupportedVersion => "Please check the KIP version supported by the system.",
            // 2xxx: Schema & Type
            Self::TypeMismatch => {
                "Execute `DESCRIBE` to confirm type names. Remember types are case-sensitive (`Drug` vs `drug`)."
            }
            Self::AttributeUndefined => {
                "Check `instance_schema`. If it's a new attribute, confirm if dynamic extension is allowed."
            }
            Self::ConstraintViolation => "Supply the missing required attributes.",
            Self::InvalidValueType => "Correct the JSON value type.",
            // 3xxx: Logic & Data
            Self::ReferenceError => {
                "Ensure the `CONCEPT` block defining the handle is placed before subsequent clauses referencing it in `UPSERT`."
            }
            Self::NotFound => {
                "Target may have been deleted or never created. Try `SEARCH` or `FIND` to confirm existence first."
            }
            Self::DuplicateExists => {
                "If intent is update, check if `UPSERT` should be used instead of creation logic."
            }
            Self::ImmutableTarget => {
                "**Operation Prohibited.** Do not attempt to modify system meta-definitions or core identity nodes."
            }
            // 4xxx: System & Execution
            Self::ExecutionTimeout => {
                "Optimize query. Reduce `UNION` usage, lower `LIMIT`, or reduce regex/hops."
            }
            Self::ResourceExhausted => "Must use `LIMIT` and `CURSOR` for pagination.",
            Self::InternalError => "Contact system administrator or retry later.",
        }
    }
}

impl Display for KipErrorCode {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.code())
    }
}

/// KIP Error type with standard error codes and messages
#[derive(Error, Debug, Clone)]
#[error("{code}: {message}")]
pub struct KipError {
    /// The standard KIP error code
    pub code: KipErrorCode,
    /// Detailed error message
    pub message: String,
}

impl KipError {
    /// Creates a new KipError with the given code and message
    pub fn new(code: KipErrorCode, message: impl Into<String>) -> Self {
        Self {
            code,
            message: message.into(),
        }
    }

    /// Returns the error code string (e.g., "KIP_1001")
    pub fn code_str(&self) -> &'static str {
        self.code.code()
    }

    /// Returns the error name (e.g., "InvalidSyntax")
    pub fn name(&self) -> &'static str {
        self.code.name()
    }

    /// Returns the recovery hint for the AI Agent
    pub fn hint(&self) -> &'static str {
        self.code.hint()
    }

    // ==================== 1xxx: Syntax & Parsing Errors ====================

    /// Creates an InvalidSyntax error (KIP_1001)
    pub fn invalid_syntax(err: impl Display) -> Self {
        Self::new(KipErrorCode::InvalidSyntax, format!("{err}"))
    }

    /// Creates an InvalidIdentifier error (KIP_1002)
    pub fn invalid_identifier(err: impl Display) -> Self {
        Self::new(KipErrorCode::InvalidIdentifier, format!("{err}"))
    }

    /// Creates an UnsupportedVersion error (KIP_1003)
    pub fn unsupported_version(err: impl Display) -> Self {
        Self::new(KipErrorCode::UnsupportedVersion, format!("{err}"))
    }

    // ==================== 2xxx: Schema & Type Errors ====================

    /// Creates a TypeMismatch error (KIP_2001)
    pub fn type_mismatch(err: impl Display) -> Self {
        Self::new(KipErrorCode::TypeMismatch, format!("{err}"))
    }

    /// Creates an AttributeUndefined error (KIP_2002)
    pub fn attribute_undefined(err: impl Display) -> Self {
        Self::new(KipErrorCode::AttributeUndefined, format!("{err}"))
    }

    /// Creates a ConstraintViolation error (KIP_2003)
    pub fn constraint_violation(err: impl Display) -> Self {
        Self::new(KipErrorCode::ConstraintViolation, format!("{err}"))
    }

    /// Creates an InvalidValueType error (KIP_2004)
    pub fn invalid_value_type(err: impl Display) -> Self {
        Self::new(KipErrorCode::InvalidValueType, format!("{err}"))
    }

    // ==================== 3xxx: Logic & Data Errors ====================

    /// Creates a ReferenceError (KIP_3001)
    pub fn reference_error(err: impl Display) -> Self {
        Self::new(KipErrorCode::ReferenceError, format!("{err}"))
    }

    /// Creates a NotFound error (KIP_3002)
    pub fn not_found(err: impl Display) -> Self {
        Self::new(KipErrorCode::NotFound, format!("{err}"))
    }

    /// Creates a DuplicateExists error (KIP_3003)
    pub fn duplicate_exists(err: impl Display) -> Self {
        Self::new(KipErrorCode::DuplicateExists, format!("{err}"))
    }

    /// Creates an ImmutableTarget error (KIP_3004)
    pub fn immutable_target(err: impl Display) -> Self {
        Self::new(KipErrorCode::ImmutableTarget, format!("{err}"))
    }

    // ==================== 4xxx: System & Execution Errors ====================

    /// Creates an ExecutionTimeout error (KIP_4001)
    pub fn execution_timeout(err: impl Display) -> Self {
        Self::new(KipErrorCode::ExecutionTimeout, format!("{err}"))
    }

    /// Creates a ResourceExhausted error (KIP_4002)
    pub fn resource_exhausted(err: impl Display) -> Self {
        Self::new(KipErrorCode::ResourceExhausted, format!("{err}"))
    }

    /// Creates an InternalError (KIP_4003)
    pub fn internal_error(err: impl Display) -> Self {
        Self::new(KipErrorCode::InternalError, format!("{err}"))
    }
}

/// Formats a nom parsing error into a KipError with detailed context
pub fn format_nom_error(input: &str, err: nom::Err<VerboseError<&str>>) -> KipError {
    let message = match err {
        nom::Err::Incomplete(needed) => {
            format!("Parse incomplete, need more input: {needed:?}")
        }
        nom::Err::Error(ve) | nom::Err::Failure(ve) => format_verbose_error(input, ve),
    };
    KipError::invalid_syntax(message)
}

fn format_verbose_error(input: &str, ve: VerboseError<&str>) -> String {
    let mut msg = String::new();
    if let Some((slice, kind)) = ve.errors.first() {
        let offending = take_first_chars(slice, 1024);
        let kind_str = match kind {
            VerboseErrorKind::Context(ctx) => format!("Context: {ctx}"),
            VerboseErrorKind::Char(c) => format!("Expected char: '{c}'"),
            VerboseErrorKind::Nom(e) => format!("Parser: {:?}", e),
        };

        let fragment = format!("{}\nOffending slice:\n{}", kind_str, offending);
        msg.push_str(&fragment);
        if offending.len() < slice.len() {
            msg.push_str("(truncated...)");
        }
        msg.push_str("\n\n");
    }

    msg.push_str(&convert_error(input, ve));

    msg
}

// 取 slice 的前 n 个字符（避免中途截断多字节字符）
fn take_first_chars(s: &str, n: usize) -> String {
    s.chars().take(n).collect()
}
