<?php
/**
 * Error Handler
 *
 * Centralized error handling for the plugin
 *
 * @package NemtlyBooking
 * @since   PBOOKING_SINCE
 */

namespace NemtlyBooking\Core;

use NemtlyBooking\Exceptions\Nemtly_Booking_Exception;
use NemtlyBooking\Exceptions\Validation_Exception;
use NemtlyBooking\Exceptions\Repository_Exception;
use NemtlyBooking\Exceptions\Service_Exception;
use WP_Error;
use WP_REST_Response;

/**
 * Error Handler class
 *
 * @since PBOOKING_SINCE
 */
class Error_Handler {

    /**
     * Handle exceptions and convert to appropriate responses
     *
     * @since PBOOKING_SINCE
     *
     * @param \Exception $exception Exception to handle.
     * @param string     $context   Error context (api, admin, frontend).
     *
     * @return WP_Error|WP_REST_Response|string Error response.
     */
    public static function handle_exception( \Exception $exception, $context = 'api' ) {
        // Log the exception
        self::log_exception( $exception );

        // Convert to appropriate response based on context
        switch ( $context ) {
            case 'api':
                return self::handle_api_exception( $exception );
            case 'admin':
                return self::handle_admin_exception( $exception );
            case 'frontend':
                return self::handle_frontend_exception( $exception );
            default:
                return self::handle_generic_exception( $exception );
        }
    }

    /**
     * Handle API exceptions
     *
     * @since PBOOKING_SINCE
     *
     * @param \Exception $exception Exception to handle.
     *
     * @return WP_Error WordPress error object.
     */
    private static function handle_api_exception( \Exception $exception ) {
        if ( $exception instanceof Nemtly_Booking_Exception ) {
            return $exception->to_wp_error();
        }

        // Generic exception handling
        return new WP_Error(
            'nemtly_booking_error',
            $exception->getMessage(),
            [
                'status'    => 500,
                'exception' => get_class( $exception ),
            ]
        );
    }

    /**
     * Handle admin exceptions
     *
     * @since PBOOKING_SINCE
     *
     * @param \Exception $exception Exception to handle.
     *
     * @return WP_Error WordPress error object.
     */
    private static function handle_admin_exception( \Exception $exception ) {
        if ( $exception instanceof Validation_Exception ) {
            $error = new WP_Error(
                'validation_failed',
                __( 'Validation failed.', 'nemtly-booking' ),
                [
                    'status'            => 400,
                    'validation_errors' => $exception->get_validation_errors(),
                ]
            );
        } elseif ( $exception instanceof Nemtly_Booking_Exception ) {
            $error = $exception->to_wp_error();
        } else {
            $error = new WP_Error(
                'nemtly_booking_error',
                __( 'An error occurred.', 'nemtly-booking' ),
                [
                    'status' => 500,
                ]
            );
        }

        // Add admin notice
        add_action(
            'admin_notices',
            function () use ( $error ) {
				$message = $error->get_error_message();
				echo '<div class="notice notice-error"><p>' . esc_html( $message ) . '</p></div>';
			}
        );

        return $error;
    }

    /**
     * Handle frontend exceptions
     *
     * @since PBOOKING_SINCE
     *
     * @param \Exception $exception Exception to handle.
     *
     * @return string Error message.
     */
    private static function handle_frontend_exception( \Exception $exception ) {
        if ( $exception instanceof Validation_Exception ) {
            $errors  = $exception->get_validation_errors();
            $message = __( 'Please check the following errors:', 'nemtly-booking' ) . '<ul>';
            foreach ( $errors as $field => $error ) {
                $message .= '<li>' . esc_html( $error ) . '</li>';
            }
            $message .= '</ul>';
        } elseif ( $exception instanceof Nemtly_Booking_Exception ) {
            $message = $exception->getMessage();
        } else {
            $message = __( 'An error occurred. Please try again.', 'nemtly-booking' );
        }

        return $message;
    }

    /**
     * Handle generic exceptions
     *
     * @since PBOOKING_SINCE
     *
     * @param \Exception $exception Exception to handle.
     *
     * @return WP_Error WordPress error object.
     */
    private static function handle_generic_exception( \Exception $exception ) {
        if ( $exception instanceof Nemtly_Booking_Exception ) {
            return $exception->to_wp_error();
        }

        return new WP_Error(
            'nemtly_booking_error',
            $exception->getMessage(),
            [
                'status' => 500,
            ]
        );
    }

    /**
     * Log exception
     *
     * @since PBOOKING_SINCE
     *
     * @param \Exception $exception Exception to log.
     */
    private static function log_exception( \Exception $exception ) {
        $log_data = [
            'message' => $exception->getMessage(),
            'file'    => $exception->getFile(),
            'line'    => $exception->getLine(),
            'trace'   => $exception->getTraceAsString(),
        ];

        if ( $exception instanceof Nemtly_Booking_Exception ) {
            $log_data['error_code'] = $exception->get_error_code();
            $log_data['error_data'] = $exception->get_error_data();
        }
    }

    /**
     * Create validation exception
     *
     * @since PBOOKING_SINCE
     *
     * @param string $message           Error message.
     * @param array  $validation_errors Validation errors.
     *
     * @return Validation_Exception Validation exception.
     */
    public static function create_validation_exception( $message, $validation_errors = [] ) {
        return new Validation_Exception( $message, $validation_errors );
    }

    /**
     * Create repository exception
     *
     * @since PBOOKING_SINCE
     *
     * @param string $message   Error message.
     * @param string $error_code Error code.
     * @param array  $error_data Error data.
     *
     * @return Repository_Exception Repository exception.
     */
    public static function create_repository_exception( $message, $error_code = 'repository_error', $error_data = [] ) {
        return new Repository_Exception( $message, $error_code, $error_data );
    }

    /**
     * Create service exception
     *
     * @since PBOOKING_SINCE
     *
     * @param string $message   Error message.
     * @param string $error_code Error code.
     * @param array  $error_data Error data.
     *
     * @return Service_Exception Service exception.
     */
    public static function create_service_exception( $message, $error_code = 'service_error', $error_data = [] ) {
        return new Service_Exception( $message, $error_code, $error_data );
    }

    /**
     * Handle WordPress errors
     *
     * @since PBOOKING_SINCE
     *
     * @param WP_Error $wp_error WordPress error object.
     * @param string   $context  Error context.
     *
     * @return WP_Error|WP_REST_Response|string Error response.
     */
    public static function handle_wp_error( WP_Error $wp_error, $context = 'api' ) {
        switch ( $context ) {
            case 'api':
                return $wp_error;
            case 'admin':
                add_action(
                    'admin_notices',
                    function () use ( $wp_error ) {
						$message = $wp_error->get_error_message();
						echo '<div class="notice notice-error"><p>' . esc_html( $message ) . '</p></div>';
					}
                );
                return $wp_error;
            case 'frontend':
                return $wp_error->get_error_message();
            default:
                return $wp_error;
        }
    }

    /**
     * Check if error is recoverable
     *
     * @since PBOOKING_SINCE
     *
     * @param \Exception $exception Exception to check.
     *
     * @return bool True if recoverable, false otherwise.
     */
    public static function is_recoverable( \Exception $exception ) {
        if ( $exception instanceof Validation_Exception ) {
            return true; // Validation errors are usually recoverable
        }

        if ( $exception instanceof Repository_Exception ) {
            return false; // Repository errors are usually not recoverable
        }

        if ( $exception instanceof Service_Exception ) {
            return true; // Service errors might be recoverable
        }

        return false; // Default to not recoverable
    }

    /**
     * Get user-friendly error message
     *
     * @since PBOOKING_SINCE
     *
     * @param \Exception $exception Exception to get message for.
     *
     * @return string User-friendly error message.
     */
    public static function get_user_friendly_message( \Exception $exception ) {
        if ( $exception instanceof Validation_Exception ) {
            return __( 'Please check your input and try again.', 'nemtly-booking' );
        }

        if ( $exception instanceof Repository_Exception ) {
            return __( 'A database error occurred. Please try again later.', 'nemtly-booking' );
        }

        if ( $exception instanceof Service_Exception ) {
            return __( 'A service error occurred. Please try again.', 'nemtly-booking' );
        }

        return __( 'An unexpected error occurred. Please try again.', 'nemtly-booking' );
    }
}
