/**
 * Mizan Server Error Types
 *
 * Typed errors for server function failures.
 */

/**
 * Error codes returned by the server
 */
export type ErrorCode =
    | 'NOT_FOUND'
    | 'VALIDATION_ERROR'
    | 'UNAUTHORIZED'
    | 'FORBIDDEN'
    | 'BAD_REQUEST'
    | 'INTERNAL_ERROR'
    | 'NOT_IMPLEMENTED'

/**
 * Error response structure from the server
 */
export interface FunctionErrorResponse {
    error: true
    code: ErrorCode
    message: string
    details?: {
        fields?: Record<string, string[]>
        required?: string[]
        type?: string
        [key: string]: unknown
    }
}

/**
 * Error thrown when a server function call fails
 */
export class MizanError extends Error {
    /**
     * Error code from the server
     */
    readonly code: ErrorCode

    /**
     * Additional error details
     */
    readonly details?: FunctionErrorResponse['details']

    /**
     * The original error response
     */
    readonly response: FunctionErrorResponse

    constructor(response: FunctionErrorResponse) {
        super(response.message)
        this.name = 'MizanError'
        this.code = response.code
        this.details = response.details
        this.response = response

        // Maintains proper stack trace for where error was thrown
        if (Error.captureStackTrace) {
            Error.captureStackTrace(this, MizanError)
        }
    }

    /**
     * Check if this is a validation error
     */
    isValidationError(): boolean {
        return this.code === 'VALIDATION_ERROR'
    }

    /**
     * Check if this is an authentication error
     */
    isAuthError(): boolean {
        return this.code === 'UNAUTHORIZED' || this.code === 'FORBIDDEN'
    }

    /**
     * Check if this is a not found error
     */
    isNotFound(): boolean {
        return this.code === 'NOT_FOUND'
    }

    /**
     * Get field-level validation errors (if this is a validation error)
     */
    getFieldErrors(): Record<string, string[]> | null {
        if (this.code === 'VALIDATION_ERROR' && this.details?.fields) {
            return this.details.fields
        }
        return null
    }

    /**
     * Get error for a specific field
     */
    getFieldError(field: string): string | null {
        const errors = this.getFieldErrors()
        if (errors && errors[field]?.length > 0) {
            return errors[field][0]
        }
        return null
    }
}
