<?php

namespace Bricksforge\ProForms;

if (!defined('ABSPATH')) exit; // Exit if accessed directly

require_once 'ProFormsLogger.php';
require_once 'AdminNotifier.php';

class LoggingActionWrapper
{
    // Static variable to track action results for form completion logging
    private static $action_results = [];
    /**
     * Execute an action with logging
     *
     * @param string $action_name The action name (e.g., 'email', 'create_post', etc.)
     * @param callable $action_callback The action to execute
     * @param \Bricksforge\ProForms\Actions\Base $base The base object
     * @return mixed The result of the action
     */
    public static function execute_with_logging($action_name, $action_callback, $base)
    {
        $form_id = $base->get_form_id();
        $post_id = $base->get_post_id();
        $form_data = $base->get_fields();

        // Don't log action start - only log results

        try {
            // Execute the action
            $result = call_user_func($action_callback);

            // Check both the return value and the base results for errors
            $success = self::is_action_successful($result, $action_name, $base);

            // Track action result for form completion logging
            self::$action_results[$form_id][$action_name] = $success;

            // Store error details if action failed
            if (!$success) {
                $error_message = self::get_error_message_from_base($base, $action_name);
                if (!isset(self::$action_results[$form_id]['_errors'])) {
                    self::$action_results[$form_id]['_errors'] = [];
                }
                self::$action_results[$form_id]['_errors'][$action_name] = $error_message ?: 'Action failed';
            }

            // Don't log individual actions anymore - they will be included in form submission details
            // Individual action results are tracked in self::$action_results for form completion logging

            return $result;
        } catch (\Exception $e) {
            // Track exception as failed action
            self::$action_results[$form_id][$action_name] = false;

            // Store exception details for form completion logging
            if (!isset(self::$action_results[$form_id]['_exceptions'])) {
                self::$action_results[$form_id]['_exceptions'] = [];
            }
            self::$action_results[$form_id]['_exceptions'][$action_name] = [
                'message' => $e->getMessage(),
                'class' => get_class($e),
                'file' => basename($e->getFile()),
                'line' => $e->getLine()
            ];

            // Re-throw the exception to maintain original behavior
            throw $e;
        } catch (\Error $e) {
            // Track error as failed action
            self::$action_results[$form_id][$action_name] = false;

            // Store error details for form completion logging
            if (!isset(self::$action_results[$form_id]['_exceptions'])) {
                self::$action_results[$form_id]['_exceptions'] = [];
            }
            self::$action_results[$form_id]['_exceptions'][$action_name] = [
                'message' => $e->getMessage(),
                'class' => get_class($e),
                'file' => basename($e->getFile()),
                'line' => $e->getLine()
            ];

            // Re-throw the error to maintain original behavior
            throw $e;
        }
    }

    /**
     * Determine if an action was successful based on its result and base results
     */
    private static function is_action_successful($result, $action_name, $base)
    {
        // First check if there are any error results set in the base
        // Base results structure: $results['error'][] = $result or $results['success'][] = $result
        $base_results = $base->results;



        if (!empty($base_results)) {
            // Check for error results
            if (isset($base_results['error']) && is_array($base_results['error'])) {
                foreach ($base_results['error'] as $error_result) {
                    // Check if this error result is for the current action
                    if (isset($error_result['action']) && $error_result['action'] === $action_name) {
                        return false; // Error found in base results
                    }
                }
            }

            // Check for danger results (alternative error type)
            if (isset($base_results['danger']) && is_array($base_results['danger'])) {
                foreach ($base_results['danger'] as $danger_result) {
                    // Check if this danger result is for the current action
                    if (isset($danger_result['action']) && $danger_result['action'] === $action_name) {
                        return false; // Danger found in base results
                    }
                }
            }
        }

        // Then check the return value patterns
        switch ($action_name) {
            case 'create_submission':
                // Check for duplicate submission result
                return !(is_array($result) && isset($result['status']) && $result['status'] === 'duplicate');

            case 'post_delete':
                // Delete action returns false on failure
                return $result !== false;

            case 'email':
            case 'mailchimp':
            case 'sendgrid':
                // Email actions return null on success, false on failure
                return $result !== false && !(is_array($result) && isset($result['error']));

            case 'webhook':
                // Webhook uses set_result() to indicate success/failure
                // We rely on the base results check above for actual status
                return $result !== false;

            case 'login':
            case 'registration':
            case 'update_user':
            case 'reset_user_password':
            case 'update_user_meta':
                // User actions typically return null on success
                return $result !== false && !(is_array($result) && isset($result['error']));

            case 'post_update':
            case 'create_post':
                // Post actions return post ID on success, WP_Error or false on failure
                return $result !== false && !is_wp_error($result);

            case 'add_option':
            case 'update_option':
            case 'delete_option':
                // Option actions return boolean or null on success
                return $result !== false;

            case 'update_post_meta':
            case 'set_storage_item':
                // Meta actions return meta ID or true on success
                return $result !== false;

            case 'wc_add_to_cart':
                // WooCommerce actions return cart key on success
                return $result !== false && !empty($result);

            case 'custom':
                // Custom actions - rely on base results check
                return $result !== false;

            default:
                // General success criteria - null is acceptable for many actions
                return $result !== false && !(is_array($result) && isset($result['error']));
        }
    }

    /**
     * Get error message from base results
     */
    private static function get_error_message_from_base($base, $action_name)
    {
        $base_results = $base->results;
        if (!empty($base_results)) {
            // Check error results
            if (isset($base_results['error']) && is_array($base_results['error'])) {
                foreach ($base_results['error'] as $error_result) {
                    if (isset($error_result['action']) && $error_result['action'] === $action_name) {
                        return $error_result['message'] ?? 'Unknown error';
                    }
                }
            }

            // Check danger results
            if (isset($base_results['danger']) && is_array($base_results['danger'])) {
                foreach ($base_results['danger'] as $danger_result) {
                    if (isset($danger_result['action']) && $danger_result['action'] === $action_name) {
                        return $danger_result['message'] ?? 'Unknown error';
                    }
                }
            }
        }
        return null;
    }



    /**
     * Log form validation errors
     */
    public static function log_validation_error($validation_result, $form_id, $post_id)
    {
        ProFormsLogger::log('form_validation', 'error', 'Form validation failed', [
            'validation_error_count' => is_array($validation_result) ? count($validation_result) : 1
        ], $form_id, $post_id);
    }

    /**
     * Log form submission start (disabled - not needed)
     */
    public static function log_form_submission_start($form_id, $post_id, $form_data)
    {
        // Don't log form submission start - only log results
    }

    /**
     * Log form submission completion
     */
    public static function log_form_submission_complete($form_id, $post_id, $actions_executed)
    {


        // Analyze action results to determine overall form status
        $action_results = self::$action_results[$form_id] ?? [];
        $successful_actions = [];
        $failed_actions = [];
        $action_details = [];

        foreach ($actions_executed as $action) {
            if (isset($action_results[$action])) {
                $action_detail = [
                    'action' => $action,
                    'status' => $action_results[$action] ? 'success' : 'error'
                ];

                // Add error message if available
                if (!$action_results[$action]) {
                    $errors = $action_results['_errors'] ?? [];
                    $exceptions = $action_results['_exceptions'] ?? [];

                    if (isset($errors[$action])) {
                        $action_detail['error_message'] = $errors[$action];
                    } elseif (isset($exceptions[$action])) {
                        $action_detail['error_message'] = $exceptions[$action]['message'];
                        $action_detail['exception_details'] = $exceptions[$action];
                    }
                    $failed_actions[] = $action;
                } else {
                    $successful_actions[] = $action;
                }

                $action_details[] = $action_detail;
            } else {
                // If not tracked, assume successful (for backward compatibility)
                $successful_actions[] = $action;
                $action_details[] = [
                    'action' => $action,
                    'status' => 'success'
                ];
            }
        }

        // Prepare context with action details
        $context = [
            'action_details' => $action_details,
            'success_count' => count($successful_actions),
            'failure_count' => count($failed_actions),
            'total_actions' => count($actions_executed)
        ];

        // Determine log level and message based on results
        if (empty($failed_actions)) {
            // All actions successful
            ProFormsLogger::log('form_submission', 'success', 'Form submission completed successfully', $context, $form_id, $post_id);
        } elseif (empty($successful_actions)) {
            // All actions failed - send admin notification
            ProFormsLogger::log('form_submission', 'error', 'Form submission failed', $context, $form_id, $post_id);

            // Send admin notification for complete failure
            AdminNotifier::notify_admin_form_failure($form_id, $post_id, $failed_actions, $action_details);
        } else {
            // Some actions failed, some succeeded
            ProFormsLogger::log('form_submission', 'warning', 'Form submission completed with partial failures', $context, $form_id, $post_id);

            // Send admin notification for partial failure (if enabled)
            AdminNotifier::notify_admin_partial_failure($form_id, $post_id, $failed_actions, $successful_actions, $action_details);
        }

        // Clean up action results for this form
        unset(self::$action_results[$form_id]);
    }

    /**
     * Check if form data contains file uploads
     */
    private static function has_file_uploads($form_data)
    {
        foreach ($form_data as $key => $value) {
            if (strpos($key, 'file') !== false || strpos($key, 'upload') !== false) {
                return true;
            }
        }
        return false;
    }
}
