<?php

namespace App\Http\Controllers\Api\Tenant;

use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\TenantAdminTokenRequest;
use App\Models\EventMember;
use App\Models\Tenant;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;

class TenantAdminTokenController extends Controller
{
    public function store(TenantAdminTokenRequest $request): JsonResponse
    {
        $credentials = $request->credentials();

        /** @var User|null $user */
        $user = User::query()->when(
            isset($credentials['email']),
            fn ($query) => $query->where('email', $credentials['email']),
            fn ($query) => $query->where('username', $credentials['username'] ?? null)
        )->first();

        if (! $user || ! Hash::check($credentials['password'], (string) $user->password)) {
            throw ValidationException::withMessages([
                'login' => [trans('auth.failed')],
            ]);
        }

        $this->ensureUserCanAccessPanel($user);

        if ($user->email_verified_at === null) {
            throw ValidationException::withMessages([
                'login' => [trans('auth.unverified')],
            ]);
        }

        [$token, $abilities] = $this->issueTokenFor($user);

        return response()->json([
            'token' => $token,
            'token_type' => 'Bearer',
            'abilities' => $abilities,
            'user' => [
                'id' => $user->id,
                'email' => $user->email,
                'name' => $user->name,
                'role' => $user->role,
                'tenant_id' => $user->tenant_id,
            ],
        ]);
    }

    public function destroy(Request $request): JsonResponse
    {
        $user = $request->user();

        $token = $user?->currentAccessToken();

        if ($token) {
            $token->delete();
        }

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

    public function me(Request $request): JsonResponse
    {
        $user = $request->user();

        /** @var Tenant|null $tenant */
        $tenant = $request->attributes->get('tenant');

        if (! $tenant && $user?->tenant_id) {
            $tenant = Tenant::query()->find($user->tenant_id);
        }

        $tenantPayload = null;
        if ($tenant) {
            $tenantPayload = [
                'id' => $tenant->id,
                'tenant_id' => $tenant->id,
                'name' => $tenant->name,
                'slug' => $tenant->slug,
                'features' => $tenant->features,
            ];
        }

        return response()->json([
            'user' => $user ? Arr::only($user->toArray(), [
                'id',
                'name',
                'email',
                'role',
                'tenant_id',
            ]) : null,
            'tenant' => $tenantPayload,
            'abilities' => $user?->currentAccessToken()?->abilities ?? [],
        ]);
    }

    public function legacyTenantMe(Request $request): JsonResponse
    {
        /** @var Tenant|null $tenant */
        $tenant = $request->attributes->get('tenant')
            ?? $request->user()?->tenant;

        if (! $tenant) {
            return response()->json([
                'error' => 'tenant_not_found',
                'message' => 'Tenant context missing.',
            ], 404);
        }

        $tenant->loadMissing('activeResellerPackage');

        $user = $request->user();
        $abilities = $user?->currentAccessToken()?->abilities ?? [];

        $fullName = null;
        if ($user) {
            $first = trim((string) ($user->first_name ?? ''));
            $last = trim((string) ($user->last_name ?? ''));
            $fullName = trim($first.' '.$last) ?: null;
        }

        $activePackage = $tenant->activeResellerPackage;

        return response()->json([
            'id' => $tenant->id,
            'tenant_id' => $tenant->id,
            'name' => $tenant->name,
            'slug' => $tenant->slug,
            'email' => $tenant->contact_email,
            'fullName' => $fullName,
            'active_reseller_package_id' => $activePackage?->id,
            'remaining_events' => $activePackage?->remaining_events ?? 0,
            'package_expires_at' => $activePackage?->expires_at,
            'features' => $tenant->features ?? [],
            'scopes' => $abilities,
        ]);
    }

    public function exchange(Request $request): JsonResponse|Response
    {
        /** @var User|null $user */
        $user = Auth::guard('web')->user();

        if (! $user) {
            return response()->noContent();
        }

        $this->ensureUserCanAccessPanel($user);

        if ($user->email_verified_at === null) {
            return response()->json([
                'error' => 'unverified',
                'message' => trans('auth.unverified'),
            ], 422);
        }

        [$token, $abilities] = $this->issueTokenFor($user);

        return response()->json([
            'token' => $token,
            'token_type' => 'Bearer',
            'abilities' => $abilities,
            'user' => [
                'id' => $user->id,
                'email' => $user->email,
                'name' => $user->name,
                'role' => $user->role,
                'tenant_id' => $user->tenant_id,
            ],
        ]);
    }

    /**
     * @return array<int, string>
     */
    private function resolveTokenAbilities(User $user): array
    {
        $abilities = ['tenant-member'];

        if ($user->tenant_id) {
            $abilities[] = 'tenant:'.$user->tenant_id;
        }

        if (in_array($user->role, ['tenant_admin', 'admin', 'super_admin', 'superadmin'], true)) {
            $abilities[] = 'tenant-admin';
        }

        if ($user->isSuperAdmin()) {
            $abilities[] = 'super-admin';
        }

        return $abilities;
    }

    /**
     * @return array{0: string, 1: array<int, string>}
     */
    private function issueTokenFor(User $user): array
    {
        $user->tokens()->where('name', 'tenant-admin')->delete();

        $abilities = $this->resolveTokenAbilities($user);
        $token = $user->createToken('tenant-admin', $abilities);

        return [$token->plainTextToken, $abilities];
    }

    private function ensureUserCanAccessPanel(User $user): void
    {
        if (in_array($user->role, ['tenant_admin', 'admin', 'super_admin', 'superadmin'], true)) {
            return;
        }

        if ($user->role === 'member' && $this->userHasCollaboratorMembership($user)) {
            return;
        }

        throw ValidationException::withMessages([
            'login' => [trans('auth.not_authorized')],
        ]);
    }

    private function userHasCollaboratorMembership(User $user): bool
    {
        if (! $user->tenant_id) {
            return false;
        }

        return EventMember::query()
            ->where('tenant_id', $user->tenant_id)
            ->where(function ($query) use ($user) {
                $query->where('user_id', $user->id)
                    ->orWhere('email', $user->email);
            })
            ->whereIn('status', ['active', 'invited'])
            ->exists();
    }
}
