<?php

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;
use App\Models\Subscription;
use App\Models\User;
use App\Models\UserApiKey;
use App\Services\Keywords\KeywordQuotaService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;

class AdminSubscriptionController extends Controller
{
    public function __construct(
        private readonly KeywordQuotaService $keywordQuota
    ) {}

    private function authorizeAdmin(Request $request): ?JsonResponse
    {
        $token = (string) config('dewemoji.admin.token', '');
        $provided = trim((string) $request->header('X-Admin-Token', ''));
        if ($token === '' || $provided === '' || ! hash_equals($token, $provided)) {
            return response()->json(['ok' => false, 'error' => 'unauthorized'], 401);
        }

        return null;
    }

    public function index(Request $request): JsonResponse
    {
        if ($res = $this->authorizeAdmin($request)) {
            return $res;
        }

        $query = Subscription::query()->with('user:id,email,name,tier');

        if ($userId = $request->query('user_id')) {
            $query->where('user_id', (int) $userId);
        }
        if ($email = $request->query('email')) {
            $query->whereHas('user', fn ($q) => $q->where('email', $email));
        }
        if ($status = $request->query('status')) {
            $query->where('status', (string) $status);
        }

        $limit = min(max((int) $request->query('limit', 50), 1), 200);
        $items = $query->orderByDesc('id')->limit($limit)->get();

        return response()->json(['ok' => true, 'items' => $items]);
    }

    public function grant(Request $request): JsonResponse
    {
        if ($res = $this->authorizeAdmin($request)) {
            return $res;
        }

        $user = $this->resolveUser($request);
        if (! $user) {
            return response()->json(['ok' => false, 'error' => 'not_found'], 404);
        }

        $plan = (string) $request->input('plan', 'personal');
        $status = (string) $request->input('status', 'active');
        $provider = (string) $request->input('provider', 'admin');
        $providerRef = (string) $request->input('provider_ref', '');
        $startedAt = $this->parseDate($request->input('started_at')) ?? now();
        $expiresAt = $this->parseDate($request->input('expires_at'));

        $sub = Subscription::create([
            'user_id' => $user->id,
            'plan' => $plan,
            'status' => $status,
            'provider' => $provider,
            'provider_ref' => $providerRef !== '' ? $providerRef : null,
            'started_at' => $startedAt,
            'expires_at' => $expiresAt,
        ]);

        if ($status === 'active') {
            $user->update(['tier' => 'personal']);
            $this->keywordQuota->enforceForUser((int) $user->id, 'personal');
        }

        return response()->json(['ok' => true, 'subscription' => $sub]);
    }

    public function revoke(Request $request): JsonResponse
    {
        if ($res = $this->authorizeAdmin($request)) {
            return $res;
        }

        $id = (int) $request->input('id', 0);
        $now = now();

        if ($id > 0) {
            $sub = Subscription::find($id);
            if (! $sub) {
                return response()->json(['ok' => false, 'error' => 'not_found'], 404);
            }
            $sub->update(['status' => 'revoked', 'expires_at' => $now]);
            $this->syncUserTier($sub->user_id);

            return response()->json(['ok' => true, 'revoked' => true]);
        }

        $user = $this->resolveUser($request);
        if (! $user) {
            return response()->json(['ok' => false, 'error' => 'not_found'], 404);
        }

        Subscription::where('user_id', $user->id)
            ->where('status', 'active')
            ->update(['status' => 'revoked', 'expires_at' => $now]);

        $this->syncUserTier($user->id);

        return response()->json(['ok' => true, 'revoked' => true]);
    }

    private function resolveUser(Request $request): ?User
    {
        if ($userId = $request->input('user_id')) {
            return User::find((int) $userId);
        }
        if ($email = $request->input('email')) {
            return User::where('email', (string) $email)->first();
        }

        return null;
    }

    private function parseDate(mixed $value): ?Carbon
    {
        if (! $value) {
            return null;
        }
        try {
            return Carbon::parse((string) $value);
        } catch (\Throwable) {
            return null;
        }
    }

    private function syncUserTier(int $userId): void
    {
        $active = Subscription::where('user_id', $userId)
            ->where('status', 'active')
            ->where(function ($q): void {
                $q->whereNull('expires_at')
                    ->orWhere('expires_at', '>', now());
            })
            ->exists();

        User::where('id', $userId)->update([
            'tier' => $active ? 'personal' : 'free',
        ]);
        $this->keywordQuota->enforceForUser($userId, $active ? 'personal' : 'free');
        if (! $active) {
            UserApiKey::where('user_id', $userId)->update(['revoked_at' => now()]);
        }
    }
}
