<?php

namespace App\Http\Controllers\Settings;

use App\Http\Controllers\Controller;
use App\Models\Workspace;
use App\Models\WorkspaceApiToken;
use App\Support\CurrentWorkspace;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use Inertia\Inertia;
use Inertia\Response;

/**
 * Workspace-scoped API tokens for first-party integrations like the
 * WordPress companion plugin. Plaintext is shown once in the flash
 * payload on create; only the sha256 hash is persisted. Revoking
 * stamps revoked_at — rows stay for audit instead of hard-deleting.
 */
class WorkspaceApiTokenController extends Controller
{
    private const SUPPORTED_ABILITIES = [
        'wp:integration',
    ];

    public function __construct(
        private readonly CurrentWorkspace $current,
    ) {}

    public function index(Request $request): Response
    {
        $workspace = $this->workspace();
        abort_unless($request->user()->can('viewAny', [WorkspaceApiToken::class, $workspace]), 403);

        $tokens = WorkspaceApiToken::query()
            ->where('workspace_id', $workspace->id)
            ->with('createdBy:id,name,email')
            ->latest()
            ->get(['id', 'name', 'abilities', 'last_used_at', 'revoked_at', 'created_at', 'created_by_user_id']);

        return Inertia::render('settings/api-tokens', [
            'tokens' => $tokens,
            'abilities' => self::SUPPORTED_ABILITIES,
            'new_token' => $request->session()->get('new_token'),
        ]);
    }

    public function store(Request $request): RedirectResponse
    {
        $workspace = $this->workspace();
        abort_unless($request->user()->can('manage', [WorkspaceApiToken::class, $workspace]), 403);

        $data = $request->validate([
            'name' => ['required', 'string', 'max:120'],
            'abilities' => ['required', 'array', 'min:1'],
            'abilities.*' => ['string', Rule::in(self::SUPPORTED_ABILITIES)],
        ]);

        // Prefix lets operators eyeball whether a leaked secret belongs
        // to Pitchbar at all before they go digging for the workspace.
        $plaintext = 'pbar_'.Str::random(48);

        // Per-token signing secret for short-lived shopper tokens
        // (CMS adapters use it to sign visitor-context claims). Stored
        // plaintext — limited blast radius (see ShopperToken).
        $shopperSigningSecret = Str::random(48);

        WorkspaceApiToken::create([
            'workspace_id' => $workspace->id,
            'created_by_user_id' => $request->user()?->id,
            'name' => $data['name'],
            'token_hash' => hash('sha256', $plaintext),
            'abilities' => array_values(array_unique($data['abilities'])),
            'shopper_signing_secret' => $shopperSigningSecret,
        ]);

        return back()
            ->with('success', 'API token created. Copy it now — it will not be shown again.')
            ->with('new_token', $plaintext);
    }

    public function destroy(Request $request, WorkspaceApiToken $token): RedirectResponse
    {
        abort_unless($request->user()->can('revoke', $token), 403);

        if ($token->revoked_at === null) {
            $token->forceFill(['revoked_at' => now()])->save();
        }

        return back()->with('success', 'Token revoked.');
    }

    private function workspace(): Workspace
    {
        $workspace = $this->current->get();
        abort_unless($workspace !== null, 404);

        return $workspace;
    }
}
