<?php

/**
 * Account Fields Service
 *
 * Renders extra profile fields and avatar on the WooCommerce
 * My Account > Account Details (edit-account) form, and handles saving.
 *
 * @package ArraySubs\Features\ProfileFields\Services
 * @since 1.9.0
 */

namespace ArraySubs\Features\ProfileFields\Services;

defined('ABSPATH') || exit;

/**
 * Account fields integration with WooCommerce My Account.
 */
class AccountFields
{
    /**
     * Enable auto-loading
     *
     * @var bool
     */
    public static $loadable = true;

    /**
     * Constructor
     */
    public function __construct()
    {
        add_action('woocommerce_edit_account_form_tag', [$this, 'addFormEnctype']);
        add_action('woocommerce_edit_account_form', [$this, 'renderAvatarSection'], 5);
        add_action('woocommerce_edit_account_form', [$this, 'renderExtraFields'], 10);
        add_action('woocommerce_save_account_details', [$this, 'saveExtraFields'], 10, 1);
        add_action('woocommerce_save_account_details_errors', [$this, 'validateExtraFields'], 10, 2);
    }

    /**
     * Add enctype to the account edit form for file uploads.
     *
     * @return void
     */
    public function addFormEnctype(): void
    {
        echo ' enctype="multipart/form-data"';
    }

    /**
     * Render avatar upload section on the edit-account form.
     *
     * @return void
     */
    public function renderAvatarSection(): void
    {
        $avatar_settings = arraysubs_get_avatar_settings();

        if (empty($avatar_settings['enabled'])) {
            return;
        }

        $user_id     = get_current_user_id();
        $avatar_data = arraysubs_get_user_avatar($user_id);
        $gravatar    = get_avatar_url($user_id, ['size' => 150]);
        $current_src = $avatar_data['has_avatar'] ? esc_url($avatar_data['url']) : $gravatar;

        include dirname(__DIR__) . '/views/avatar-section.php';
    }

    /**
     * Render extra profile fields on the edit-account form.
     *
     * @return void
     */
    public function renderExtraFields(): void
    {
        $fields  = arraysubs_get_enabled_profile_fields();
        $user_id = get_current_user_id();

        if (empty($fields)) {
            return;
        }

        echo '<div class="arraysubs-profile-fields">';
        echo '<h3>' . esc_html__('Additional Information', 'arraysubs') . '</h3>';

        foreach ($fields as $field) {
            if ('upload' === $field['type']) {
                $this->renderUploadField($field, $user_id);
            } else {
                $this->renderField($field, $user_id);
            }
        }

        echo '</div>';

        wp_nonce_field('arraysubs_save_profile_fields', 'arraysubs_profile_fields_nonce');
    }

    /**
     * Render a single profile field.
     *
     * @param array $field   Field definition.
     * @param int   $user_id User ID.
     * @return void
     */
    private function renderField(array $field, int $user_id): void
    {
        $value       = arraysubs_get_user_profile_field($user_id, $field['key']);
        $field_name  = 'arraysubs_pf_' . esc_attr($field['key']);
        $field_id    = 'arraysubs-pf-' . esc_attr($field['key']);
        $required    = !empty($field['required']);
        $req_attr    = $required ? ' required="required"' : '';
        $req_marker  = $required ? '&nbsp;<span class="required">*</span>' : '';
        $placeholder = esc_attr($field['placeholder'] ?? '');

        echo '<p class="woocommerce-form-row woocommerce-form-row--wide form-row form-row-wide arraysubs-profile-field">';
        echo '<label for="' . esc_attr($field_id) . '">';
        echo esc_html($field['label']);
        echo wp_kses_post($req_marker);
        echo '</label>';

        switch ($field['type']) {
            case 'text':
                echo '<input type="text" class="woocommerce-Input woocommerce-Input--text input-text" name="' . esc_attr($field_name) . '" id="' . esc_attr($field_id) . '" value="' . esc_attr($value) . '" placeholder="' . $placeholder . '"' . $req_attr . ' />';
                break;

            case 'textarea':
                echo '<textarea class="woocommerce-Input woocommerce-Input--textarea input-text" name="' . esc_attr($field_name) . '" id="' . esc_attr($field_id) . '" rows="4" placeholder="' . $placeholder . '"' . $req_attr . '>' . esc_textarea($value) . '</textarea>';
                break;

            case 'select':
                echo '<select class="woocommerce-Input woocommerce-Input--select input-select" name="' . esc_attr($field_name) . '" id="' . esc_attr($field_id) . '"' . $req_attr . '>';
                echo '<option value="">' . esc_html__('Select an option', 'arraysubs') . '</option>';
                if (!empty($field['options']) && is_array($field['options'])) {
                    foreach ($field['options'] as $option) {
                        $selected = selected($value, $option['value'], false);
                        echo '<option value="' . esc_attr($option['value']) . '"' . $selected . '>' . esc_html($option['label']) . '</option>';
                    }
                }
                echo '</select>';
                break;

            case 'date':
                echo '<input type="date" class="woocommerce-Input woocommerce-Input--date input-text" name="' . esc_attr($field_name) . '" id="' . esc_attr($field_id) . '" value="' . esc_attr($value) . '"' . $req_attr . ' />';
                break;

            case 'checkbox':
                $checked = checked($value, '1', false);
                echo '<label class="arraysubs-profile-field__checkbox-label">';
                echo '<input type="checkbox" class="woocommerce-Input woocommerce-Input--checkbox input-checkbox" name="' . esc_attr($field_name) . '" id="' . esc_attr($field_id) . '" value="1"' . $checked . ' />';
                echo ' ' . esc_html($field['placeholder'] ?? $field['label']);
                echo '</label>';
                break;
        }

        if (!empty($field['help_text'])) {
            echo '<span class="arraysubs-profile-field__help">' . esc_html($field['help_text']) . '</span>';
        }

        echo '</p>';
    }

    /**
     * Render a file upload field.
     *
     * @param array $field   Field definition.
     * @param int   $user_id User ID.
     * @return void
     */
    private function renderUploadField(array $field, int $user_id): void
    {
        $value      = arraysubs_get_user_profile_field($user_id, $field['key']);
        $field_name = 'arraysubs_pf_' . esc_attr($field['key']);
        $field_id   = 'arraysubs-pf-' . esc_attr($field['key']);
        $required   = !empty($field['required']);
        $req_marker = $required ? '&nbsp;<span class="required">*</span>' : '';
        $max_size   = !empty($field['max_file_size']) ? absint($field['max_file_size']) : 5;
        $allowed    = !empty($field['allowed_types']) ? implode(', ', $field['allowed_types']) : '';

        echo '<p class="woocommerce-form-row woocommerce-form-row--wide form-row form-row-wide arraysubs-profile-field arraysubs-profile-field--upload" data-field-key="' . esc_attr($field['key']) . '">';
        echo '<label for="' . esc_attr($field_id) . '">';
        echo esc_html($field['label']);
        echo wp_kses_post($req_marker);
        echo '</label>';

        echo '<span class="arraysubs-profile-field__upload-wrapper">';

        if (!empty($value)) {
            $upload_dir = arraysubs_get_profile_upload_dir($user_id);
            $file_url   = $upload_dir['url'] . '/' . $value;
            echo '<span class="arraysubs-profile-field__current-file">';
            echo '<a href="' . esc_url($file_url) . '" target="_blank" rel="noopener noreferrer">' . esc_html(basename($value)) . '</a>';
            echo ' <button type="button" class="arraysubs-profile-field__remove-file button" data-field="' . esc_attr($field['key']) . '">' . esc_html__('Remove', 'arraysubs') . '</button>';
            echo '</span>';
            echo '<input type="hidden" name="' . esc_attr($field_name) . '_existing" value="' . esc_attr($value) . '" />';
        }

        echo '<input type="file" class="woocommerce-Input woocommerce-Input--file" name="' . esc_attr($field_name) . '" id="' . esc_attr($field_id) . '" data-max-size="' . esc_attr($max_size) . '" />';
        echo '</span>';

        $help_parts = [];
        if (!empty($allowed)) {
            /* translators: %s: comma-separated list of allowed file extensions */
            $help_parts[] = sprintf(esc_html__('Allowed types: %s', 'arraysubs'), esc_html($allowed));
        }
        /* translators: %d: maximum file size in megabytes */
        $help_parts[] = sprintf(esc_html__('Max size: %d MB', 'arraysubs'), $max_size);

        if (!empty($field['help_text'])) {
            $help_parts[] = esc_html($field['help_text']);
        }

        echo '<span class="arraysubs-profile-field__help">' . implode(' &middot; ', $help_parts) . '</span>';
        echo '</p>';
    }

    /**
     * Validate extra fields before saving.
     *
     * @param \WP_Error $errors WP_Error object.
     * @param object    $user   User object from WC.
     * @return void
     */
    public function validateExtraFields(\WP_Error $errors, $user): void
    {
        if (
            !isset($_POST['arraysubs_profile_fields_nonce'])
            || !wp_verify_nonce(
                sanitize_text_field(wp_unslash($_POST['arraysubs_profile_fields_nonce'])),
                'arraysubs_save_profile_fields'
            )
        ) {
            return;
        }

        $fields = arraysubs_get_enabled_profile_fields();

        foreach ($fields as $field) {
            if (empty($field['required'])) {
                continue;
            }

            $field_name = 'arraysubs_pf_' . $field['key'];

            if ('checkbox' === $field['type']) {
                continue;
            }

            if ('upload' === $field['type']) {
                $has_existing = !empty($_POST[$field_name . '_existing']);
                $has_new_file = !empty($_FILES[$field_name]['name']);
                if (!$has_existing && !$has_new_file) {
                    /* translators: %s: field label */
                    $errors->add('required_field', sprintf(esc_html__('%s is required.', 'arraysubs'), esc_html($field['label'])));
                }
                continue;
            }

            if (empty($_POST[$field_name])) {
                /* translators: %s: field label */
                $errors->add('required_field', sprintf(esc_html__('%s is required.', 'arraysubs'), esc_html($field['label'])));
            }
        }
    }

    /**
     * Save extra fields when the edit-account form is submitted.
     *
     * @param int $user_id User ID.
     * @return void
     */
    public function saveExtraFields(int $user_id): void
    {
        if (
            !isset($_POST['arraysubs_profile_fields_nonce'])
            || !wp_verify_nonce(
                sanitize_text_field(wp_unslash($_POST['arraysubs_profile_fields_nonce'])),
                'arraysubs_save_profile_fields'
            )
        ) {
            return;
        }

        $fields = arraysubs_get_enabled_profile_fields();

        foreach ($fields as $field) {
            $field_name = 'arraysubs_pf_' . $field['key'];

            if ('upload' === $field['type']) {
                $this->handleFileUpload($field, $field_name, $user_id);
                continue;
            }

            if ('checkbox' === $field['type']) {
                $value = isset($_POST[$field_name]) ? '1' : '0';
                arraysubs_save_user_profile_field($user_id, $field['key'], $value);
                continue;
            }

            if (!isset($_POST[$field_name])) {
                continue;
            }

            $raw_value = wp_unslash($_POST[$field_name]);

            switch ($field['type']) {
                case 'textarea':
                    $value = sanitize_textarea_field($raw_value);
                    break;
                case 'date':
                    $value = sanitize_text_field($raw_value);
                    if (!empty($value) && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) {
                        $value = '';
                    }
                    break;
                case 'select':
                    $value      = sanitize_text_field($raw_value);
                    $valid_vals = array_column($field['options'] ?? [], 'value');
                    if (!in_array($value, $valid_vals, true)) {
                        $value = '';
                    }
                    break;
                default:
                    $value = sanitize_text_field($raw_value);
                    break;
            }

            arraysubs_save_user_profile_field($user_id, $field['key'], $value);
        }
    }

    /**
     * Handle file upload for an upload-type field.
     *
     * @param array  $field      Field definition.
     * @param string $field_name POST field name.
     * @param int    $user_id    User ID.
     * @return void
     */
    private function handleFileUpload(array $field, string $field_name, int $user_id): void
    {
        $remove_key = 'arraysubs_remove_file_' . $field['key'];
        if (isset($_POST[$remove_key]) && sanitize_text_field(wp_unslash($_POST[$remove_key]))) {
            $old_file = arraysubs_get_user_profile_field($user_id, $field['key']);
            if (!empty($old_file)) {
                $upload_dir = arraysubs_get_profile_upload_dir($user_id);
                $old_path   = $upload_dir['path'] . '/' . $old_file;
                if (file_exists($old_path)) {
                    wp_delete_file($old_path);
                }
                arraysubs_save_user_profile_field($user_id, $field['key'], '');
            }
            return;
        }

        if (empty($_FILES[$field_name]['name'])) {
            return;
        }

        $allowed_types = $field['allowed_types'] ?? ['jpg', 'jpeg', 'png', 'pdf', 'doc', 'docx'];
        $max_size_mb   = $field['max_file_size'] ?? 5;
        $max_size      = $max_size_mb * MB_IN_BYTES;

        $file = $_FILES[$field_name];

        if ($file['error'] !== UPLOAD_ERR_OK) {
            return;
        }

        if ($file['size'] > $max_size) {
            return;
        }

        $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        if (!in_array($ext, $allowed_types, true)) {
            return;
        }

        $wp_filetype = wp_check_filetype($file['name']);
        if (empty($wp_filetype['type'])) {
            return;
        }

        $upload_dir = arraysubs_get_profile_upload_dir($user_id);

        if (!file_exists($upload_dir['path'])) {
            wp_mkdir_p($upload_dir['path']);
        }

        arraysubs_protect_upload_dir($upload_dir['path'], true);

        $old_file = arraysubs_get_user_profile_field($user_id, $field['key']);
        if (!empty($old_file)) {
            $old_path = $upload_dir['path'] . '/' . $old_file;
            if (file_exists($old_path)) {
                wp_delete_file($old_path);
            }
        }

        $safe_name = wp_unique_filename($upload_dir['path'], sanitize_file_name($file['name']));
        $dest      = $upload_dir['path'] . '/' . $safe_name;

        if (move_uploaded_file($file['tmp_name'], $dest)) {
            arraysubs_save_user_profile_field($user_id, $field['key'], $safe_name);
        }
    }
}
