<?php
declare(strict_types=1);

namespace EHxMe\Shortcodes;

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

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

class CustomFormShortcode
{
    private string $shortcode_id;
    public Response $response;
    const NONCE_ACTION = 'ehxme_custom_form_submit';
    const TRANSIENT_PREFIX = 'ehxme_form_attrs_';
    const TOKEN_EXPIRY = 3600; // 1 hour in seconds

    /**
     * Constructor for the EHxMe_Custom_Form_Shortcode class.
     */
    public function __construct()
    {
        $this->response = new Response();

        add_shortcode('ehxme_member_form', [$this, 'addShortcode']);

        add_action('wp_ajax_ehxme_custom_form_submit', [$this, 'handleFormSubmit']);
        add_action('wp_ajax_nopriv_ehxme_custom_form_submit', [$this, 'handleFormSubmit']);
    }
    
    /**
     * Register the shortcode to display the form.
     *
     * @param array $atts Shortcode attributes.
     * @return string HTML output of the form.
     */
    public function addShortcode($atts = array())
    {
        if (is_user_logged_in()) {
            return $this->getErrorMessage(__('You are logged in user.', 'ehx-members'));
        }
        
        $atts = $this->parseShortcodeAttributes($atts);
        $shortcode_id = self::TRANSIENT_PREFIX . wp_rand(1000, 9999);
        $this->shortcode_id = $shortcode_id;

        set_transient($this->shortcode_id, $atts, self::TOKEN_EXPIRY);

        if ($atts['type'] === 'reset') {
            $validate = $this->handleResetTokenValidation($atts);
            
            if(gettype($validate) !== 'array') return $validate;
        }

        return View::render('shortcodes/custom-form', [
            'atts' => $atts,
            'shortcode_id' => $shortcode_id,
            'validate' => $validate ?? [],
        ], true);
    }
    
    /**
     * Handle form submission via AJAX.
     */
    public function handleFormSubmit()
    {
        try {
            $request = new Request();

            $request->verify(self::NONCE_ACTION);
        
            if (!$request->input('shortcode_id')) {
                throw new Exception(esc_html__('Form session expired. Please try again.', 'ehx-members'));
            }
            
            $attrs = $this->getFormAttributes($request);

            $email = $request->input('email');

            $user = get_user_by('email', $email);

            if (!$user) {
                throw new Exception(esc_html__('Email not found.', 'ehx-members'));
            }

            if ($attrs['type'] === 'reset') {
                return $this->handlePasswordReset($request, $user, $attrs);
            } else {
                return $this->handlePasswordResetRequest($user, $attrs);
            }
        } catch (Exception $e) {
            return $this->response->error($e->getMessage());
        }
    }

    /***************************
     * PRIVATE HELPER METHODS
     ***************************/

    /**
     * Parse and validate shortcode attributes.
     */
    private function parseShortcodeAttributes($atts)
    {
        $defaults = [
            'type' => 'forget',
            'reset_page' => '/reset-password',
            'login_page' => '/login',
        ];

        $atts = shortcode_atts($defaults, array_change_key_case((array) $atts));
        
        return $atts;
    }

    /**
     * Validate reset token.
     */
    private function handleResetTokenValidation($atts)
    {
        $request = new Request();
        $email = $request->input('email');
        $token = $request->input('token');

        if (empty($email) || empty($token)) {
            return $this->getErrorMessage(__('Invalid or expired token.', 'ehx-members'));
        }

        $user = get_user_by('email', $email);
        if (!$user) {
            return $this->getErrorMessage(__('Invalid or expired token.', 'ehx-members'));
        }

        $saved_token = get_user_meta($user->ID, '_ehx_reset_token', true);
        $expiry = get_user_meta($user->ID, '_ehx_token_expiry', true);

        if ($token !== $saved_token || time() > $expiry) {
            return $this->getErrorMessage(__('Invalid or expired token.', 'ehx-members'));
        }

        return ['email' => $email, 'token' => $token];
    }

    /**
     * Get form attributes from transient.
     */
    private function getFormAttributes(Request $request)
    {
        $attrs = get_transient($request->input('shortcode_id'));
        if ($attrs === false) {
            throw new Exception(esc_html__('Form session expired. Please try again.', 'ehx-members'));
        }
        return $attrs;
    }

    /**
     * Handle password reset process.
     */
    private function handlePasswordReset(Request $request, $user, $attrs)
    {
        $validator = new Validator();

        $validator->validate([
            'password' => 'required|string|min:8|same:confirm_password'
        ]);

        $saved_token = get_user_meta($user->ID, '_ehx_reset_token', true);
        $expiry = get_user_meta($user->ID, '_ehx_token_expiry', true);

        if ($request->input('token') !== $saved_token || time() > $expiry) {
            throw new Exception(esc_html__('Invalid or expired token.', 'ehx-members'));
        }

        wp_set_password($request->input('password'), $user->ID);
        delete_user_meta($user->ID, '_ehx_reset_token');
        delete_user_meta($user->ID, '_ehx_token_expiry');

        return $this->response->success(
            __('Password successfully updated.', 'ehx-members'), 
            ['redirect' => $attrs['login_page']]
        );
    }

    /**
     * Handle password reset request.
     */
    private function handlePasswordResetRequest($user, $attrs)
    {
        $token = wp_generate_password(20, false);
        update_user_meta($user->ID, '_ehx_reset_token', $token);
        update_user_meta($user->ID, '_ehx_token_expiry', time() + self::TOKEN_EXPIRY);

        $reset_url = add_query_arg([
            'email' => $user->user_email,
            'token' => $token
        ], site_url($attrs['reset_page']));

        $subject = __('Reset Your Password', 'ehx-members');
        ob_start();
        require EHXME_PLUGIN_DIR . 'views/mail/reset-password.php';
        $message = ob_get_clean();

        Helper::send_email($user->user_email, $subject, $message);

        return $this->response->success(
            __('Check your email for reset instructions.', 'ehx-members')
        );
    }

    /**
     * Get error message HTML.
     */
    private function getErrorMessage($message)
    {
        return '<p>' . esc_html($message) . '</p>';
    }

    /**
     * Generates an HTML input field with label and validation message.
     *
     * @param string $label The label text for the input field.
     * @param string $for The 'for' attribute value for the label. If not provided, defaults to the $label.
     * @param string $isType The type of input field. Can be 'input', 'select', or 'textarea'. Defaults to 'input'.
     * @param string $placeholder The placeholder text for the input field.
     * @param bool $required Whether the input field is required. Defaults to true.
     *
     * @return void Prints the HTML for the input field with label and validation message.
     */
    public static function inputField($label = '', $for = '', $isType = 'input', $placeholder = '', $data = [], $type = 'text', $required = true, $column = 'ehx-input-box-full')
    {
        $htmlFor = $for != null ? $for : $label;
        $isRequired = $required ? 'required' : '';

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