<?php
declare(strict_types=1);

namespace EHxMe\Shortcodes;

use EHxMe\Classes\Settings;
use EHxMe\Classes\View;
use EHxMe\Helpers\Helper;
use EHxMe\Models\Payment;
use EHxMe\Services\Request;
use EHxMe\Services\Response;
use EHxMe\Services\Validator;
use Exception;

if (!defined('ABSPATH')) {
    exit;
}

class FormShortcode
{
    public Response $response;
    const NONCE_ACTION = 'ehxme_from_submit';

    public $form_id;

    /**
     * Constructor for the FormShortcode class.
     *
     * Initializes the response object and adds the shortcode for the member form.
     * Also sets up the AJAX actions for handling form submissions.
     */
    public function __construct()
    {
        // Initialize the response object
        $this->response = new Response();

        // Add the shortcode for the member form
        add_shortcode('ehxmember', [$this, 'addShortcode']);

        // Set up the AJAX actions for handling form submissions
        add_action('wp_ajax_ehxme_from_submit', [$this, 'handleFormSubmit']); // When user is logged in
        add_action('wp_ajax_nopriv_ehxme_from_submit', [$this, 'handleFormSubmit']); // When user is logged out
    }
    
    /**
     * Register the shortcode to display the form.
     *
     * @param array $attr Shortcode attributes.
     */
    public function addShortcode($atts = array(), $content = null, $tag = '')
    {
        $atts = shortcode_atts($atts, array_change_key_case((array) $atts), $tag);

        extract($atts);

        [$post, $ehx_custom_fields, $ehx_form] = self::getField($form_id);

        $ehx_mode = isset($ehx_form['_ehx_mode']) ? $ehx_form['_ehx_mode'] : 'register';
        
        $load_stripe = isset($ehx_form['member_role']) && $ehx_form['member_role'] == 'paid_member' && (bool) Settings::extractSettingValue('stripe_enable', false);

        if (in_array($ehx_mode, ['register','login'])) {
            if (is_user_logged_in()) {
                return '<p>'.esc_html__('You are already registered.', 'ehx-members').'</p>';
            }
        }
        elseif($ehx_mode == 'profile') {
            if (!is_user_logged_in()) {
                return '<p>'.esc_html__('Please login your account first.', 'ehx-members').'</p>';
            }
        }

        $is_active_donate_plugin = is_plugin_active('ehx-donate/ehx-donate.php');
        if($is_active_donate_plugin) {
            // require_once EHXDO_PLUGIN_DIR . 'classes/class.ehx-donate-donation.php';
            // $donations = EHXDo_Donation_Data_Table::get_data();
            $donations = [];
        }

        $is_active_event_plugin = is_plugin_active('ehx-event/ehx-event.php');
        if($is_active_event_plugin) {
            // $bookings = \EHxEvent\Classes\BookingDataTable::getData();
            $bookings = [];
        }

        $payments = Helper::getPayments();

        foreach ($ehx_custom_fields as $field) {
            if (isset($field['_type']) && in_array($field['_type'], ['select', 'multiselect'])) {
                wp_enqueue_style('ehxme-select2');
                wp_enqueue_script('ehxme-select2');

                break;
            }
        }

        if (isset($ehx_form['_ehx_mode']) && $ehx_form['_ehx_mode'] == 'profile') {
            wp_enqueue_script('ehxme-bootstrap');
        }

        if ($load_stripe) {
            wp_enqueue_script('ehxme-stripe');
        }

        if($ehx_mode == 'profile') {
            wp_enqueue_style('ehxme-datatable');
            wp_enqueue_script('ehxme-datatable');
        }

        return View::render('shortcodes/form', [
            'form_id' => $form_id,
            'post' => $post,
            'ehx_form' => $ehx_form,
            'ehx_mode' => $ehx_mode,
            'is_active_donate_plugin' => $is_active_donate_plugin,
            'is_active_event_plugin' => $is_active_event_plugin,
            'load_stripe' => $load_stripe,
            'ehx_custom_fields' => $ehx_custom_fields,
            'payments' => $payments,
            'donations' => $donations ?? [],
            'bookings' => $bookings ?? [],
        ], true);
    }
    
    /**
     * Handle user registration, login, and profile updates.
     *
     * @return mixed Success response with message and optional redirect URL, error response with error message.
     */
    public function handleFormSubmit()
    {
        $request = new Request();

        // Validate nonce to prevent CSRF
        $request->verify(self::NONCE_ACTION);

        $validator = new Validator();

        // Get form post data
        [$post, $ehx_custom_fields, $ehx_form] = self::getField($request->input('form_id'));

        // Validate form mode
        if (!isset($ehx_form['_ehx_mode'])) {
            return $this->response->error(esc_html__('Invalid form mode.', 'ehx-members'));
        }

        // Define validation rules and validate input data
        $rules = Helper::extractRules($ehx_custom_fields);
        
        $validator->validate($rules);
        $validatedData = $validator->validated();

        $predefinedFields = ['user_login', 'user_pass', 'user_email', 'display_name', 'user_nicename', 'role', 'user_status'];

        $userData = [];
        $userMetaData = [];
        foreach ($validatedData as $key => $value) {
            if (in_array($key, $predefinedFields)) {
                $userData[$key] = $value;
            }
            else {
                if ($request->hasFile($key)) {
                    if ($request->file($key)['error'] === UPLOAD_ERR_OK) {
                        // Include necessary WordPress files
                        require_once ABSPATH . 'wp-admin/includes/image.php';
                        require_once ABSPATH . 'wp-admin/includes/file.php';
                        require_once ABSPATH . 'wp-admin/includes/media.php';
                
                        // Upload the image to the Media Library
                        $attachment_id = media_handle_upload($key, 0);
                        
                        $userMetaData[$key] = $attachment_id;
                    }
                }
                else {
                    $userMetaData[$key] = $value;
                }
            }
        }
        $userMetaData['form_id'] = $request->input('form_id');

        if($ehx_form['_ehx_mode'] == 'register') {
            $userData['role'] =  isset($userData['role']) ? $userData['role'] : ($ehx_form['member_role'] ?? 'free_member');
        }

        if (!isset($userData['display_name']) || (isset($userData['display_name']) && empty($userData['display_name']))) {
            $userData['display_name'] = $request->input('name') ?? $request->input('full_name') ?? $request->input('user_name');
            if (empty($userData['display_name']) && $request->filled('first_name')) {
                $userData['display_name'] = $request->input('first_name');
                if ($request->filled('last_name')) {
                    $userData['display_name'] .= ' ' . $request->input('last_name');
                }
            }
        }
        else {
            $userData['display_name'] = null;
        }

        if (!isset($userData['user_login'])) {
            // Initialize the login variable with a default value
            $user_login = $request->input('username');

            if (empty($user_login)) {
                // If no login field is found, generate a login from the display name
                if (!empty($userData['display_name'])) {
                    $user_login = str_replace(' ', '-', strtolower($userData['display_name']));
                }
                else {
                    $loginFields = ['user_email', 'email'];
                    // Loop through possible login fields
                    foreach ($loginFields as $field) {
                        if ($request->filled($field)) {
                            $user_login = $request->input($field);
                            break; // Exit loop once a login field is found
                        }
                    }
                }
            }
            // Assign the login to userData
            $userData['user_login'] = $user_login;
        }

        $userData['user_nicename'] = !empty($userData['user_nicename']) ? $userData['user_nicename'] : $userData['user_login'];

        if (!isset($userData['user_email'])) {
            $emailFields = ['email', 'username', 'email_address'];
            $user_email = null;
        
            foreach ($emailFields as $field) {
                if ($request->filled($field)) {
                    $input = $request->input($field);
                    if (filter_var($input, FILTER_VALIDATE_EMAIL)) {
                        $user_email = $input;
                        break;
                    }
                }
            }
            $userData['user_email'] = $user_email;
        }

        if (!isset($userData['user_pass'])) {
            // List of possible password field names
            $passwordFields = ['password', 'user_password', 'passwords', 'users_pass', 'users_password'];
        
            // Initialize the password variable with a default value
            $user_pass = null;
        
            // Loop through possible password fields
            foreach ($passwordFields as $field) {
                if ($request->filled($field)) {
                    $user_pass = $request->input($field);
                    break; // Exit loop once a password is found
                }
            }
        
            // Assign the password to userData
            $userData['user_pass'] = $user_pass;
        }

        $load_stripe = isset($ehx_form['member_role']) && $ehx_form['member_role'] == 'paid_member' && (bool) Settings::extractSettingValue('stripe_enable', false);
        
        $charge = null;
        if ($load_stripe) {
            $amount = $ehx_form['ehx_amount'];
            if($amount > 0) {
                $stripe_token = $request->input('stripe_token');

                if (!$stripe_token) {
                    return $this->response->error(esc_html__('Please give your card details.', 'ehx-members'));
                }

                $stripeToken  = gettype($stripe_token) == 'string' ? json_decode($stripe_token) : $stripe_token;
                $token_id = gettype($stripeToken) == 'array' ? $stripeToken['id'] : $stripeToken->id;
                $stripe = new \Stripe\StripeClient(esc_attr(Settings::extractSettingValue('stripe_client_secret')));

                try {
                    $charge = $stripe->charges->create([
                        'amount' => $amount * 100,
                        'currency' => 'gbp',
                        'source' => $token_id,
                        'receipt_email' => $userData['user_email'],
                    ]);

                } catch (Exception $e) {
                    return $this->response->error($e->getMessage());
                }
            }
        }
        
        switch ($ehx_form['_ehx_mode']) {
            case 'register':
                $message = $this->handleRegistration($userData, $userMetaData);
                break;
            case 'login':
                $message = $this->handleLogin($userData, $userMetaData);
                break;
            case 'profile':
                $message = $this->handleProfile($userData, $userMetaData);
                break;
            default:
                return $this->response->error(esc_html__('Invalid form mode.', 'ehx-members'));
        }

        if (!empty($charge)) {
            $user = get_user_by( 'email', $userData['user_email']);

            (new Payment)->create([
                'user_id' => $user->ID,
                'amount'  => $amount,
                'charge'  => 0,
                'method'  => 'stripe',
                'status'  => 'success',
                'additional_data'  => wp_json_encode($charge),
            ]);
        }

        // Determine redirect URL
        $redirect = $this->getRedirectUrl($ehx_form);
        
        // Success response
        return $this->response->success($message, !empty($redirect) ? ['redirect' => $redirect] : []);
    }

    /**
     * Handles user registration.
     *
     * @param array $userData User data for registration.
     * @param array $userMetaData Additional user metadata.
     *
     * @return mixed User data on success, error message on failure.
     */
    private function handleRegistration(array $userData, array $userMetaData)
    {
        // Register the user
        $user_id = wp_insert_user($userData);
        if (is_wp_error($user_id)) {
            return $this->response->error($user_id->get_error_message());
        }

        global $wpdb;
        $wpdb->update($wpdb->users, ['user_status' => $userData['user_status'] ?? 1], ['id' => $user_id]);

        // Store additional user metadata
        foreach ($userMetaData as $key => $value) {
            if (in_array($key, ['first_name', 'last_name'])) {
                update_user_meta($user_id, $key, $value);
            }
        }
        update_user_meta($user_id, 'ehxme_user', $userMetaData);

        self::sendConfirmationMail($userData['user_email'], $userData);

        $admin_email_address = Settings::extractSettingValue('admin_email_address');
        if(!empty($admin_email_address)) {
            self::sendConfirmationMail($admin_email_address, $userData, true);
        }  

        return $this->handleSignin($userData, $userMetaData);
    }

    /**
     * Handles user login.
     *
     * @param array $userData User data for login.
     * @param array $userMetaData Additional user metadata.
     *
     * @return mixed User data on success, error message on failure.
     */
    private function handleLogin(array $userData, array $userMetaData)
    {
        return $this->handleSignin($userData, $userMetaData, true);
    }
    
    /**
     * Handles user signon (login or registration).
     *
     * @param array $userData User data for login or registration.
     * @param array $userMetaData Additional user metadata.
     * @param bool $login Whether to perform a login instead of registration.
     *
     * @return mixed Success message or error message.
     */
    private function handleSignin(array $userData, array $userMetaData, $login = false)
    {
        // Determine the user field for login verification
        $login_fields = [
            'user_login' => $userData['user_login'] ?? '',
            'user_email' => $userData['user_email'] ?? ($userData['email'] ?? ''),
            'username'   => $userMetaData['username'] ?? '',
        ];

        $field = '';
        $value = '';

        foreach ($login_fields as $val) {
            if (!empty($val)) {
                $field = is_email($val) ? 'email' : 'login';
                $value = $val;
                break;
            }
        }

        if (empty($field) || empty($value)) {
            return $this->response->error(__('Missing login credentials.', 'ehx-members'));
        }

        // Password validation
        if (empty($userData['user_pass'])) {
            return $this->response->error(__('Password is required.', 'ehx-members'));
        }

        // Retrieve user data
        $user_data = get_user_by($field, $value);
        if (!$user_data || !wp_check_password($userData['user_pass'], $user_data->user_pass, $user_data->ID)) {
            return $this->response->error(__('These credentials do not match our records.', 'ehx-members'));
        }

        if ($login && !$user_data->user_status) {
            return $this->response->error(__('Your account are currently inactive, please contact admin.', 'ehx-members'));
        }

        // Auto-login after registration
        wp_signon([
            'user_login'    => $user_data->user_login,
            'user_password' => $userData['user_pass'],
            'remember'      => !empty($userData['remember']),
        ]);

        if($login) {
            return esc_html__('You are logged in successfully!', 'ehx-members');
        }
        return esc_html__('Registration completed successfully!', 'ehx-members');
    }

    /**
     * Handles user profile.
     *
     * @param array $userData User data for profile update.
     * @param array $userMetaData Additional user metadata.
     */
    private function handleProfile(array $userData, array $userMetaData)
    {
        $user_id = wp_update_user(array_merge(['ID' => get_current_user_id()], $userData));

        if (is_wp_error($user_id)) {
            return $this->response->error($user_id->get_error_message());
        }

        // Update additional user metadata
        foreach ($userMetaData as $key => $value) {
            if (in_array($key, ['first_name', 'last_name'])) {
                update_user_meta($user_id, $key, $value);
            }
        }

        update_user_meta($user_id, 'ehxme', $userMetaData);

        return esc_html__('Profile updated successfully!', 'ehx-members');
    }

    /**
     * Determines the redirect URL after login/registration.
     *
     * @param array $ehx_form The form data array.
     *
     * @return string|null The redirect URL or null if no redirect is required.
     */
    private function getRedirectUrl($ehx_form)
    {
        if (!isset($ehx_form['login_after_login'])) {
            return null;
        }

        return match($ehx_form['login_after_login']) {
            'redirect_profile' => '/profile',
            'redirect_url' => $ehx_form['login_redirect_url'] ?? '/',
            'refresh' => isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : null,
            'redirect_admin' => '/wp-admin/index.php',
            default => null,
        };
    }

    /**
     * Register the shortcode to display the form.
     *
     * @param array $attr Shortcode attributes.
     */
    public static function inputField($field = array(), $isBootstrap = false)
    {
        $metaKey  = $field['_metakey'];
        $required = (isset($field['_required']) && $field['_required']) || str_contains($field['_validate'], 'required') ? true : false;
        $class  = $isBootstrap ? 'form-control' : 'ehx-input';
        $column = $isBootstrap ? 'form-group' : 'ehx-input-box';
        if ($field['_column'] == '2') {
            $column .= $isBootstrap ? ' col-12' : ' ehx-input-box-full';
        }
        else {
            $column .= $isBootstrap ? ' col-md-6' : '';
        }

        if (in_array($field['_type'], ['select', 'multiselect'])) {
            $class .= ' ehx-select2';
        }

        $options = explode(',', $field['_options']);
        $allowed_types = $field['_type'] == 'file' && !empty($field['_type'] == 'file') ? json_decode($field['_allowed_types']) : [];

        $user = wp_get_current_user();

        $predefinedFields = ['user_login', 'user_pass', 'user_email', 'display_name', 'user_nicename'];

        $value = $field['_default'];
        if (is_user_logged_in() && !current_user_can('manage_options')) {
            if (in_array($metaKey, $predefinedFields)) {
                $value = $user->{$metaKey};
            }
            else {
                // $value = get_user_meta($user->ID, $metaKey, true);
                $user_meta = get_user_meta($user->ID, 'ehxme', true);
                $value = isset($user_meta[$metaKey]) ? $user_meta[$metaKey] : null;
            }
        }

        require EHXME_PLUGIN_DIR . 'views/frontend/inc/form-input-field.php';
    }

    /**
     * Retrieves the post and associated custom fields for a given form ID.
     *
     * @param int $form_id The ID of the form.
     *
     * @return array An array containing the post object, custom fields, and form data.
     */
    private static function getField($form_id): array
    {
        $post = get_post($form_id);
        $ehx_custom_fields = get_post_meta($post->ID, '_ehx_custom_field', true) ?? [];
        $ehx_form = get_post_meta($post->ID, 'ehx_form', true) ?? [];

        return [$post, $ehx_custom_fields, $ehx_form];
    }

    /**
    * Sends a confirmation email to a user or admin based on the provided parameters.
    *
    * @param string $to The email address to send the confirmation email to.
    * @param array $userData An associative array containing the user's data, including 'user_email', 'display_name', and 'user_login'.
    * @param bool $isAdmin A flag indicating whether the email is being sent to an admin (default is false).
    *
    * @return void
    */
    public static function sendConfirmationMail($to, $userData, $isAdmin = false)
    {
        $fromName = Settings::extractSettingValue('mail_appears_from', get_bloginfo('name'));

        /* translators: 
        * %s: The name of the website/organization 
        * Context: Email subject line for welcome/new user notifications
        */
        $subject = !$isAdmin ? sprintf(esc_html__('Welcome to %s!', 'ehx-members'), $fromName) : sprintf(esc_html__('New User Registration - %s', 'ehx-members'), $fromName);

        $message = View::render('mail/registration-confirmation', [
            'fromName' => $fromName,
            'subject' => $subject,
            'userData' => $userData,
            'isAdmin' => $isAdmin
        ], true);

        // Send email to user
        Helper::send_email($to, $subject, $message);
    }

}