<?php

/**
 * Admin User Profile Fields
 *
 * Renders and saves extra profile fields on the WP Admin user
 * edit / create pages.
 *
 * @package ArraySubs\Features\ProfileFields\Services
 * @since 1.9.0
 */

namespace ArraySubs\Features\ProfileFields\Services;

defined('ABSPATH') || exit;

use ArraySubs\Supports\Config;

/**
 * Admin user profile fields integration.
 */
class AdminFields
{
    /**
     * Enable auto-loading
     *
     * @var bool
     */
    public static $loadable = true;

    /**
     * Constructor
     */
    public function __construct()
    {
        add_action('show_user_profile', [$this, 'renderFields'], 20);
        add_action('edit_user_profile', [$this, 'renderFields'], 20);
        add_action('user_new_form', [$this, 'renderFieldsOnCreate'], 20);
        add_action('user_edit_form_tag', [$this, 'addFormEnctype']);
        add_action('admin_enqueue_scripts', [$this, 'enqueueAdminStyles']);

        add_action('personal_options_update', [$this, 'saveFields']);
        add_action('edit_user_profile_update', [$this, 'saveFields']);
        add_action('user_register', [$this, 'saveFields']);

        add_filter('get_avatar_url', [$this, 'filterAvatarUrl'], 10, 3);
    }

    /**
     * Enqueue admin styles on user edit/create pages.
     *
     * @param string $hook Current admin page hook.
     * @return void
     */
    public function enqueueAdminStyles(string $hook): void
    {
        if (!in_array($hook, ['profile.php', 'user-edit.php', 'user-new.php'], true)) {
            return;
        }

        $asset_file = Config::get('plugin.public_path') . 'build/profile-fields.asset.php';
        $version    = file_exists($asset_file) ? require($asset_file) : ['version' => ARRAYSUBS_VERSION];

        wp_enqueue_style(
            'arraysubs-admin-profile-fields',
            Config::get('plugin.public_url') . 'build/profile-fields.css',
            [],
            $version['version']
        );
    }

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

    /**
     * Render profile fields on the user edit page.
     *
     * @param \WP_User $user User object.
     * @return void
     */
    public function renderFields(\WP_User $user): void
    {
        $fields          = arraysubs_get_enabled_profile_fields();
        $avatar_settings = arraysubs_get_avatar_settings();

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

        if (!current_user_can('edit_user', $user->ID)) {
            return;
        }

        include dirname(__DIR__) . '/views/admin-user-fields.php';
    }

    /**
     * Render profile fields on the user create page.
     *
     * @param string $operation The operation context (add-new-user).
     * @return void
     */
    public function renderFieldsOnCreate(string $operation): void
    {
        if ('add-new-user' !== $operation) {
            return;
        }

        $fields          = arraysubs_get_enabled_profile_fields();
        $avatar_settings = arraysubs_get_avatar_settings();

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

        $user = null;
        include dirname(__DIR__) . '/views/admin-user-fields.php';
    }

    /**
     * Save profile fields from the admin user form.
     *
     * @param int $user_id User ID.
     * @return void
     */
    public function saveFields(int $user_id): void
    {
        if (
            !isset($_POST['arraysubs_admin_profile_nonce'])
            || !wp_verify_nonce(
                sanitize_text_field(wp_unslash($_POST['arraysubs_admin_profile_nonce'])),
                'arraysubs_admin_save_profile_fields'
            )
        ) {
            return;
        }

        if (!current_user_can('edit_user', $user_id)) {
            return;
        }

        $fields = arraysubs_get_enabled_profile_fields();

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

            if ('upload' === $field['type']) {
                $this->handleAdminFileUpload($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);
        }

        $this->handleAdminAvatarUpload($user_id);
    }

    /**
     * Handle admin file upload for upload-type fields.
     *
     * @param array  $field      Field definition.
     * @param string $field_name POST field name.
     * @param int    $user_id    User ID.
     * @return void
     */
    private function handleAdminFileUpload(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);
        }
    }

    /**
     * Handle avatar upload from admin user edit page.
     *
     * @param int $user_id User ID.
     * @return void
     */
    private function handleAdminAvatarUpload(int $user_id): void
    {
        $avatar_settings = arraysubs_get_avatar_settings();

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

        if (isset($_POST['arraysubs_remove_avatar']) && sanitize_text_field(wp_unslash($_POST['arraysubs_remove_avatar']))) {
            arraysubs_delete_user_avatar($user_id);
            return;
        }

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

        $file     = $_FILES['arraysubs_avatar'];
        $max_size = ($avatar_settings['max_file_size'] ?? 2) * MB_IN_BYTES;

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

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

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

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

        $upload_dir = arraysubs_get_avatar_upload_dir();

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

        arraysubs_protect_upload_dir($upload_dir['path']);

        arraysubs_delete_user_avatar($user_id);

        $safe_name = $user_id . '-' . wp_generate_password(12, false) . '.' . $ext;
        $dest      = $upload_dir['path'] . '/' . $safe_name;

        if (move_uploaded_file($file['tmp_name'], $dest)) {
            update_user_meta($user_id, 'arraysubs_avatar', $safe_name);
        }
    }

    /**
     * Filter avatar URL to use the custom avatar if set.
     *
     * @param string $url         Default avatar URL.
     * @param mixed  $id_or_email User ID, email, or WP_User.
     * @param array  $args        Avatar arguments.
     * @return string
     */
    public function filterAvatarUrl(string $url, $id_or_email, array $args): string
    {
        $user_id = 0;

        if (is_numeric($id_or_email)) {
            $user_id = absint($id_or_email);
        } elseif (is_string($id_or_email)) {
            $user = get_user_by('email', $id_or_email);
            if ($user) {
                $user_id = $user->ID;
            }
        } elseif ($id_or_email instanceof \WP_User) {
            $user_id = $id_or_email->ID;
        } elseif ($id_or_email instanceof \WP_Post) {
            $user_id = (int) $id_or_email->post_author;
        } elseif ($id_or_email instanceof \WP_Comment) {
            if (!empty($id_or_email->user_id)) {
                $user_id = (int) $id_or_email->user_id;
            }
        }

        if ($user_id <= 0) {
            return $url;
        }

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

        $avatar_data = arraysubs_get_user_avatar($user_id);
        if ($avatar_data['has_avatar'] && !empty($avatar_data['file_path']) && file_exists($avatar_data['file_path'])) {
            return $avatar_data['url'];
        }

        return $url;
    }
}
