<?php

/**
 * LoginAsUser Admin Hooks
 *
 * Adds "Login as User" buttons across admin screens:
 * - Users list column
 * - User edit / profile page (JS injection near the h1 heading)
 * - WooCommerce order edit actions box
 * - Subscription detail page (REST filter)
 * - Member detail pages (via the subscription detail REST data)
 *
 * @package ArraySubs\Features\LoginAsUser\Services
 * @since 1.0.0
 */

namespace ArraySubs\Features\LoginAsUser\Services;

defined('ABSPATH') || exit;

use ArraySubs\Supports\Config;

/**
 * Admin hooks for the Login as User feature.
 */
class AdminHooks
{
    /**
     * Enable auto-loading.
     *
     * @var bool
     */
    public static $loadable = true;

    /**
     * Constructor — registers admin hooks.
     */
    public function __construct()
    {
        // Users list: column + content
        add_filter('manage_users_columns', [$this, 'addUsersColumn'], 100);
        add_filter('manage_users_custom_column', [$this, 'renderUsersColumnContent'], 15, 3);

        // User edit / profile page: JS button near heading
        add_action('admin_enqueue_scripts', [$this, 'enqueueAdminAssets']);

        // WooCommerce order edit: existing order actions metabox
        add_action('woocommerce_order_actions_start', [$this, 'renderOrderActionsButton']);

        // Subscription detail REST response: append login_as_user_url
        add_filter('arraysubs_subscription_detail_data', [$this, 'appendLoginAsUserToDetail'], 10, 2);

        // Member profile REST response: append login_as_user_url
        add_filter('arraysubs_member_profile_data', [$this, 'appendLoginAsUserToProfile'], 10, 2);

        // Admin styles for the button
        add_action('admin_enqueue_scripts', [$this, 'enqueueAdminStyles']);
    }

    // ------------------------------------------------------------------
    // Users list
    // ------------------------------------------------------------------

    /**
     * Add "Login as User" column to the users list table.
     *
     * @param array $columns Existing columns.
     * @return array
     */
    public function addUsersColumn(array $columns): array
    {
        $new_columns = [];

        foreach ($columns as $key => $label) {
            $new_columns[$key] = $label;
            if ('username' === $key) {
                $new_columns['arraysubs_login_as_user'] = esc_html__('Login as User', 'arraysubs');
            }
        }

        if (!isset($new_columns['arraysubs_login_as_user'])) {
            $new_columns['arraysubs_login_as_user'] = esc_html__('Login as User', 'arraysubs');
        }

        return $new_columns;
    }

    /**
     * Render content for the Login as User column on the users list.
     *
     * @param string $output      Current column output.
     * @param string $column_name Column name.
     * @param int    $user_id     User ID.
     * @return string
     */
    public function renderUsersColumnContent(string $output, string $column_name, int $user_id): string
    {
        if ('arraysubs_login_as_user' !== $column_name) {
            return $output;
        }

        return $this->generateButton($user_id, 'column');
    }

    // ------------------------------------------------------------------
    // User edit / profile page heading button
    // ------------------------------------------------------------------

    /**
     * Enqueue the user profile heading button script.
     *
     * @param string $hook Current admin page hook.
     * @return void
     */
    public function enqueueAdminAssets(string $hook): void
    {
        if (!$this->isUserProfilePage($hook)) {
            return;
        }

        $user_id = $this->getProfileUserId();

        if (!$user_id) {
            return;
        }

        $target_user = get_userdata($user_id);
        if (!$target_user) {
            return;
        }

        $button_data = $this->getButtonData($user_id);

        $asset_file = Config::get('plugin.public_path') . 'build/admin/login-as-user-profile-btn.asset.php';
        $asset = file_exists($asset_file)
            ? require $asset_file
            : ['dependencies' => ['wp-dom-ready', 'wp-i18n'], 'version' => ARRAYSUBS_VERSION];

        wp_enqueue_script(
            'arraysubs-login-as-user-profile-btn',
            Config::get('plugin.public_url') . 'build/admin/login-as-user-profile-btn.js',
            $asset['dependencies'],
            $asset['version'],
            true
        );

        wp_set_script_translations(
            'arraysubs-login-as-user-profile-btn',
            'arraysubs',
            Config::get('plugin.path') . 'languages'
        );

        wp_add_inline_script(
            'arraysubs-login-as-user-profile-btn',
            'window.arraySubsLoginAsUser = ' . wp_json_encode(
                [
                    'loginUrl'     => $button_data['url'],
                    'displayName'  => $button_data['display_name'],
                    'isAvailable'  => $button_data['available'],
                    'reason'       => $button_data['reason'],
                ],
                JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT
            ) . ';',
            'before'
        );
    }

    // ------------------------------------------------------------------
    // WooCommerce order edit actions box
    // ------------------------------------------------------------------

    /**
     * Render the Login as Customer button inside WooCommerce's order actions box.
     *
     * @param int $order_id Order ID.
     * @return void
     */
    public function renderOrderActionsButton(int $order_id): void
    {
        $order = wc_get_order($order_id);

        if (!$order) {
            return;
        }

        $customer_id = $order->get_customer_id();

        if (!$customer_id) {
            return;
        }

        echo '<li class="wide arraysubs-login-as-user-order-action">';
        echo wp_kses_post($this->generateButton($customer_id, 'order-actions'));
        echo '</li>';
    }

    // ------------------------------------------------------------------
    // Subscription detail REST filter
    // ------------------------------------------------------------------

    /**
     * Append login_as_user_url to the subscription detail REST response.
     *
     * @param array $data            Subscription detail data.
     * @param int   $subscription_id Subscription ID.
     * @return array
     */
    public function appendLoginAsUserToDetail(array $data, int $subscription_id): array
    {
        $customer_id = isset($data['customer_id']) ? (int) $data['customer_id'] : 0;

        if ($customer_id <= 0) {
            return $data;
        }

        $button_data = $this->getButtonData($customer_id);

        $data['login_as_user_url']        = $button_data['url'];
        $data['login_as_user_available']  = $button_data['available'];
        $data['login_as_user_reason']     = $button_data['reason'];

        return $data;
    }

    // ------------------------------------------------------------------
    // Member profile REST filter
    // ------------------------------------------------------------------

    /**
     * Append login_as_user_url to the member profile REST response.
     *
     * @param array $profile_data Profile data array.
     * @param int   $user_id      User ID.
     * @return array
     */
    public function appendLoginAsUserToProfile(array $profile_data, int $user_id): array
    {
        if ($user_id <= 0) {
            return $profile_data;
        }

        $button_data = $this->getButtonData($user_id);

        $profile_data['login_as_user_url']       = $button_data['url'];
        $profile_data['login_as_user_available'] = $button_data['available'];
        $profile_data['login_as_user_reason']    = $button_data['reason'];

        return $profile_data;
    }

    // ------------------------------------------------------------------
    // Admin styles
    // ------------------------------------------------------------------

    /**
     * Enqueue admin CSS for the login-as-user buttons.
     *
     * @param string $hook Current admin hook.
     * @return void
     */
    public function enqueueAdminStyles(string $hook): void
    {
        $allowed_hooks = [
            'users.php',
            'user-edit.php',
            'profile.php',
            'woocommerce_page_wc-orders',
        ];

        // Also load on the arraysubs admin page (subscription/member detail).
        $is_plugin_page = strpos($hook, 'arraysubs') !== false;
        $order_post_id  = filter_input(INPUT_GET, 'post', FILTER_VALIDATE_INT);
        $is_order_page  = 'post.php' === $hook && $order_post_id && 'shop_order' === get_post_type($order_post_id);

        if (!in_array($hook, $allowed_hooks, true) && !$is_plugin_page && !$is_order_page) {
            return;
        }

        $asset_file = Config::get('plugin.public_path') . 'build/admin/login-as-user-admin.asset.php';
        $asset_version = file_exists($asset_file)
            ? (require $asset_file)['version'] ?? ARRAYSUBS_VERSION
            : ARRAYSUBS_VERSION;

        wp_enqueue_style(
            'arraysubs-login-as-user-admin',
            Config::get('plugin.public_url') . 'build/admin/login-as-user-admin.css',
            [],
            $asset_version
        );
    }

    // ------------------------------------------------------------------
    // Helpers
    // ------------------------------------------------------------------

    /**
     * Generate a Login as User button for a given user.
     *
     * @param int    $user_id Target user ID.
     * @param string $scope   Either "column" or an action button context.
     * @return string Escaped HTML.
     */
    private function generateButton(int $user_id, string $scope = 'column'): string
    {
        $button_data = $this->getButtonData($user_id);

        $btn_class = 'button arraysubs-login-as-user-btn';

        if ('order-actions' === $scope) {
            $btn_class .= ' arraysubs-login-as-user-btn--order-actions';
        }

        if (!$button_data['available']) {
            if ('column' === $scope) {
                return '<span class="arraysubs-login-as-user-msg" title="' . esc_attr($button_data['reason']) . '">' . esc_html($button_data['reason']) . '</span>';
            }

            return sprintf(
                '<button type="button" class="%1$s arraysubs-login-as-user-btn--disabled" disabled="disabled" title="%2$s"><span class="dashicons dashicons-admin-users"></span> %3$s</button>',
                esc_attr($btn_class),
                esc_attr($button_data['reason']),
                esc_html__('Login as Customer', 'arraysubs')
            );
        }

        return sprintf(
            '<a class="%s" href="%s" title="%s"><span class="dashicons dashicons-admin-users"></span> %s <strong>%s</strong></a>',
            esc_attr($btn_class),
            esc_url($button_data['url']),
            /* translators: %s: user display name */
            esc_attr(sprintf(__('Login as %s', 'arraysubs'), $button_data['display_name'])),
            esc_html__('Login as', 'arraysubs'),
            esc_html($button_data['display_name'])
        );
    }

    /**
     * Get normalized button data for a target user.
     *
     * @param int $user_id Target user ID.
     * @return array<string,mixed>
     */
    private function getButtonData(int $user_id): array
    {
        $default = [
            'url'          => '',
            'available'    => false,
            'reason'       => esc_html__('Not allowed.', 'arraysubs'),
            'display_name' => esc_html__('Customer', 'arraysubs'),
        ];

        if ($user_id <= 0) {
            $default['reason'] = esc_html__('No user available.', 'arraysubs');
            return $default;
        }

        $target_user = get_userdata($user_id);

        if (!$target_user) {
            $default['reason'] = esc_html__('User not found.', 'arraysubs');
            return $default;
        }

        $default['display_name'] = $target_user->display_name ?: $target_user->user_login;

        if (get_current_user_id() === $user_id) {
            $default['reason'] = esc_html__('You cannot log in as your own account.', 'arraysubs');
            return $default;
        }

        if (user_can($target_user, 'manage_options')) {
            $default['reason'] = esc_html__('Administrator accounts cannot be impersonated.', 'arraysubs');
            return $default;
        }

        if (!current_user_can('arraysubs_login_as_user', $user_id)) {
            $default['reason'] = esc_html__('You are not allowed to impersonate this user.', 'arraysubs');
            return $default;
        }

        $login_url = Impersonator::buildLoginUrl($target_user);

        if (!$login_url) {
            return $default;
        }

        $default['url'] = $login_url;
        $default['available'] = true;
        $default['reason'] = '';

        return $default;
    }

    /**
     * Check if the current admin page is a user profile screen.
     *
     * @param string $hook Current admin hook.
     * @return bool
     */
    private function isUserProfilePage(string $hook): bool
    {
        if (!current_user_can('manage_woocommerce') && !current_user_can('manage_options')) {
            return false;
        }

        return in_array($hook, ['profile.php', 'user-edit.php'], true);
    }

    /**
     * Get the user ID being viewed on a profile/user-edit page.
     *
     * @return int
     */
    private function getProfileUserId(): int
    {
        $user_id = filter_input(INPUT_GET, 'user_id', FILTER_VALIDATE_INT);

        if ($user_id) {
            return $user_id;
        }

        return get_current_user_id();
    }
}
