<?php

namespace App\Support;

use App\Models\Event;
use App\Models\EventMember;
use App\Models\User;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\Response;

class TenantMemberPermissions
{
    /**
     * @return array<int, string>
     */
    public static function resolveEventPermissions(Request $request, Event $event): array
    {
        $user = $request->user();

        if (! $user instanceof User) {
            return [];
        }

        if (self::isTenantAdmin($user)) {
            return ['*'];
        }

        $member = self::resolveEventMember($user, $event);

        if (! $member) {
            return [];
        }

        return self::normalizePermissions($member->permissions);
    }

    public static function ensureEventPermission(Request $request, Event $event, string $permission): void
    {
        if (self::allowsPermission(self::resolveEventPermissions($request, $event), $permission)) {
            return;
        }

        throw new HttpResponseException(ApiError::response(
            'insufficient_permission',
            'Insufficient permission',
            'You are not allowed to perform this action.',
            Response::HTTP_FORBIDDEN,
            ['required_permission' => $permission]
        ));
    }

    public static function allowsEventPermission(Request $request, Event $event, string $permission): bool
    {
        return self::allowsPermission(self::resolveEventPermissions($request, $event), $permission);
    }

    public static function ensureTenantPermission(Request $request, string $permission): void
    {
        $user = $request->user();

        if (! $user instanceof User) {
            throw new HttpResponseException(ApiError::response(
                'unauthenticated',
                'Unauthenticated',
                'You must be authenticated to perform this action.',
                Response::HTTP_UNAUTHORIZED
            ));
        }

        if (self::isTenantAdmin($user)) {
            return;
        }

        $permissions = self::resolveTenantMemberPermissions($user);

        if (self::allowsPermission($permissions, $permission)) {
            return;
        }

        throw new HttpResponseException(ApiError::response(
            'insufficient_permission',
            'Insufficient permission',
            'You are not allowed to perform this action.',
            Response::HTTP_FORBIDDEN,
            ['required_permission' => $permission]
        ));
    }

    /**
     * @return array<int, string>
     */
    private static function resolveTenantMemberPermissions(User $user): array
    {
        if (! $user->tenant_id) {
            return [];
        }

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

        $permissions = [];

        foreach ($memberships as $member) {
            $permissions = array_merge($permissions, self::normalizePermissions($member->permissions));
        }

        return array_values(array_unique($permissions));
    }

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

    private static function resolveEventMember(User $user, Event $event): ?EventMember
    {
        return EventMember::query()
            ->where('tenant_id', $event->tenant_id)
            ->where('event_id', $event->id)
            ->whereIn('status', ['active', 'invited'])
            ->where(function ($query) use ($user) {
                $query->where('user_id', $user->id)
                    ->orWhere('email', $user->email);
            })
            ->first();
    }

    /**
     * @param  array<int, string>|string|null  $permissions
     * @return array<int, string>
     */
    private static function normalizePermissions(mixed $permissions): array
    {
        if (is_array($permissions)) {
            return array_values(array_filter(array_map('strval', $permissions)));
        }

        if (is_string($permissions) && $permissions !== '') {
            return array_values(array_filter(array_map('trim', explode(',', $permissions))));
        }

        return [];
    }

    /**
     * @param  array<int, string>  $permissions
     */
    private static function allowsPermission(array $permissions, string $permission): bool
    {
        foreach ($permissions as $entry) {
            if ($entry === '*' || $entry === $permission) {
                return true;
            }

            if (Str::endsWith($entry, ':*')) {
                $prefix = Str::beforeLast($entry, '*');

                if (Str::startsWith($permission, $prefix)) {
                    return true;
                }
            }
        }

        return false;
    }
}
