<?php
/**
 * BacklinkStatusActions (TODO-CLIENT-007, 2026-08-02).
 *
 * Per-row action handlers for the operator's own backlinks
 * (My Backlinks tab). Provides:
 *   - Retract (pause): POST /v1/backlinks/update with status=paused
 *   - Reactivate (resume): POST /v1/backlinks/update with status=active
 *   - Delete (soft-delete): POST /v1/backlinks/delete
 *   - Check still alive (recheck): POST /v1/backlinks/source-check/recheck
 *
 * UI lives on the BacklinksHubPage "My Backlinks" tab. Source URLs become
 * clickable + open in new tab. Action buttons are per-row.
 *
 * @package SwapAds\Client\Admin
 * @since   1.5.10
 */

declare(strict_types=1);

namespace SwapAds\Client\Admin;

use SwapAds\Client\Admin\BacklinksHubPage;
use SwapAds\Client\Api\RestClient;
use SwapAds\Client\Http\Redirect;
use SwapAds\Client\Http\Request;

final class BacklinkStatusActions
{
    public const NONCE_ACTION = 'swapads_client_backlink_status_action';

    public const FLASH_ERROR   = 'swapads_client_backlink_status_flash';
    public const FLASH_SUCCESS = 'swapads_client_backlink_status_ok';

    /**
     * Register WP hooks.
     *
     * @since 1.5.10
     */
    public static function register(): void
    {
        add_action('admin_post_swapads_client_backlink_retract',      [self::class, 'handleRetract']);
        add_action('admin_post_swapads_client_backlink_reactivate',   [self::class, 'handleReactivate']);
        add_action('admin_post_swapads_client_backlink_delete',       [self::class, 'handleDelete']);
        add_action('admin_post_swapads_client_backlink_recheck',      [self::class, 'handleRecheck']);
    }

    /**
     * Render the row of per-backlink buttons (Retract / Reactivate / Delete / Recheck).
     *
     * Each button is its own form so the admin_post action is unambiguous.
     * Only the buttons valid for the current status are shown.
     *
     * @param array<string, mixed> $it Backlink row from the server.
     *
     * @since 1.5.10
     */
    public static function renderRowActions(array $it): string
    {
        $id = (int) ($it['id'] ?? 0);
        $status = (string) ($it['status'] ?? '');
        if ($id <= 0) {
            return '';
        }

        $html = '<div class="swapads-row-actions" style="display:flex;flex-wrap:wrap;gap:4px;">';

        // ACTIVE -> Retract + Delete
        if ($status === 'active') {
            $html .= self::renderButton($id, 'retract', 'Retract', 'button-small');
            $html .= self::renderButton($id, 'delete', 'Delete', 'button-small button-link-delete');
        }
        // PAUSED -> Reactivate + Delete
        elseif ($status === 'paused') {
            $html .= self::renderButton($id, 'reactivate', 'Reactivate', 'button-small');
            $html .= self::renderButton($id, 'delete', 'Delete', 'button-small button-link-delete');
        }
        // DEPLETED -> Reactivate
        elseif ($status === 'depleted') {
            $html .= self::renderButton($id, 'reactivate', 'Reactivate', 'button-small');
        }
        // REMOVED -> no row actions

        // Recheck button (for all actionable statuses)
        if (in_array($status, ['active', 'paused', 'depleted'], true)) {
            $html .= self::renderButton($id, 'recheck', 'Check still alive', 'button-small');
        }

        $html .= '</div>';
        return $html;
    }

    /**
     * Render a single action button wrapped in a form.
     *
     * @since 1.5.10
     */
    private static function renderButton(int $id, string $action, string $label, string $cssClass = 'button'): string
    {
        $actionUrl = esc_url(admin_url('admin-post.php'));
        $nonce = wp_create_nonce(self::NONCE_ACTION);
        $backUrl = esc_url(add_query_arg('tab', BacklinksHubPage::TAB_MY, admin_url('admin.php?page=' . BacklinksHubPage::MENU_SLUG)));
        return sprintf(
            '<form method="post" action="%s" style="display:inline;">'
                . '<input type="hidden" name="action" value="swapads_client_backlink_%s">'
                . '<input type="hidden" name="_wpnonce" value="%s">'
                . '<input type="hidden" name="backlink_id" value="%d">'
                . '<input type="hidden" name="_redirect_back" value="%s">'
                . '<button type="submit" class="button %s">%s</button>'
            . '</form>',
            $actionUrl,
            esc_attr($action),
            esc_attr($nonce),
            $id,
            esc_attr($backUrl),
            esc_attr($cssClass),
            esc_html($label)
        );
    }

    /**
     * Handle the "Retract" action (pause).
     *
     * @since 1.5.10
     */
    public static function handleRetract(): void
    {
        self::handleStatusUpdate('paused', 'retract');
    }

    /**
     * Handle the "Reactivate" action (resume).
     *
     * @since 1.5.10
     */
    public static function handleReactivate(): void
    {
        self::handleStatusUpdate('active', 'reactivate');
    }

    /**
     * Handle the "Delete" action (soft-delete).
     *
     * @since 1.5.10
     */
    public static function handleDelete(): void
    {
        if (!current_user_can('manage_options')) {
            wp_die('Insufficient permissions', 'Forbidden', ['response' => 403]);
        }
        check_admin_referer(self::NONCE_ACTION);

        $backlinkId = Request::inputInt('backlink_id', 0, 'post');
        $back       = Request::input('_redirect_back', '', 'post');

        if ($backlinkId <= 0) {
            self::flashError('Invalid backlink id', $back);
            return;
        }

        $client = RestClient::fromOption();
        try {
            $resp = $client->deleteBacklink($backlinkId);
        } catch (\Throwable $e) {
            self::flashError('Could not delete: ' . $e->getMessage(), $back);
            return;
        }

        if (is_array($resp) && !empty($resp['success'])) {
            self::flashSuccess('Backlink deleted.', $back);
        } else {
            self::flashError('Server returned an error.', $back);
        }
    }

    /**
     * Handle the "Check still alive" action (recheck source URL).
     *
     * @since 1.5.10
     */
    public static function handleRecheck(): void
    {
        if (!current_user_can('manage_options')) {
            wp_die('Insufficient permissions', 'Forbidden', ['response' => 403]);
        }
        check_admin_referer(self::NONCE_ACTION);

        $backlinkId = Request::inputInt('backlink_id', 0, 'post');
        $back       = Request::input('_redirect_back', '', 'post');

        if ($backlinkId <= 0) {
            self::flashError('Invalid backlink id', $back);
            return;
        }

        $client = RestClient::fromOption();
        try {
            $resp = $client->post('/v1/backlinks/source-check/recheck', ['backlink_ids' => [$backlinkId]]);
        } catch (\Throwable $e) {
            self::flashError('Could not recheck: ' . $e->getMessage(), $back);
            return;
        }

        if (is_array($resp) && !empty($resp['success'])) {
            self::flashSuccess('Source check triggered.', $back);
        } else {
            self::flashError('Server returned an error.', $back);
        }
    }

    /**
     * Common handler for status-update actions (retract / reactivate).
     *
     * @since 1.5.10
     */
    private static function handleStatusUpdate(string $newStatus, string $label): void
    {
        if (!current_user_can('manage_options')) {
            wp_die('Insufficient permissions', 'Forbidden', ['response' => 403]);
        }
        check_admin_referer(self::NONCE_ACTION);

        $backlinkId = Request::inputInt('backlink_id', 0, 'post');
        $back       = Request::input('_redirect_back', '', 'post');

        if ($backlinkId <= 0) {
            self::flashError('Invalid backlink id', $back);
            return;
        }

        $client = RestClient::fromOption();
        try {
            $resp = $client->updateBacklink($backlinkId, ['status' => $newStatus]);
        } catch (\Throwable $e) {
            self::flashError("Could not {$label}: " . $e->getMessage(), $back);
            return;
        }

        if (is_array($resp) && !empty($resp['success'])) {
            self::flashSuccess("Backlink {$label}d.", $back);
        } else {
            self::flashError('Server returned an error.', $back);
        }
    }

    /**
     * Persist a success flash transient + redirect.
     *
     * @since 1.5.10
     */
    private static function flashSuccess(string $message, string $back): void
    {
        set_transient(self::FLASH_SUCCESS, [
            'error_code'  => 'OK',
            'http_status' => 200,
            'message'     => $message,
            'when'        => time(),
        ], MINUTE_IN_SECONDS);
        Redirect::to($back !== '' ? $back : self::fallbackRedirect());
    }

    /**
     * Persist an error flash transient + redirect.
     *
     * @since 1.5.10
     */
    private static function flashError(string $message, string $back): void
    {
        set_transient(self::FLASH_ERROR, [
            'error_code'  => 'STATUS_ACTION_FAILED',
            'http_status' => 500,
            'message'     => $message,
            'when'        => time(),
        ], MINUTE_IN_SECONDS);
        Redirect::to($back !== '' ? $back : self::fallbackRedirect());
    }

    /**
     * Fallback redirect target (My Backlinks tab).
     *
     * @since 1.5.10
     */
    private static function fallbackRedirect(): string
    {
        return admin_url('admin.php?page=' . BacklinksHubPage::MENU_SLUG . '&tab=' . BacklinksHubPage::TAB_MY);
    }
}
