<?php

declare(strict_types=1);

namespace Builder\Core\Http\Controllers\Concerns;

use Builder\Core\Exceptions\DeletionDeniedException;
use Builder\Core\Exceptions\ResourceNotFoundException;
use Builder\Core\Exceptions\UnauthorizedAccessException;
use Builder\Core\Foundation\Contracts\BuilderAccessible;
use Builder\Core\Foundation\Middleware\BuilderAuth;
use Builder\Core\Foundation\Registry;
use Builder\Core\Foundation\Resources\ResourceDefinition;
use Builder\Core\Models\Language;
use Illuminate\Http\Request;

/**
 * @property-read Registry $registry
 */
trait HasResourceResolving
{
    protected function resolveOrFail(string $slug): ResourceDefinition
    {
        $definition = $this->registry->resolveBySlug($slug);

        if ($definition === null) {
            throw ResourceNotFoundException::forSlug($slug);
        }

        return $definition;
    }

    protected function authorizeResource(Request $request, ResourceDefinition $definition, string $action): void
    {
        $permission = $definition->resolvePermissionForAction($action);

        if ($permission === null) {
            return;
        }

        /** @var BuilderAccessible $user */
        $user = $request->user(BuilderAuth::guard());
        $permissions = $user->builderPermissions();

        if (in_array('*', $permissions, true) || in_array($permission, $permissions, true)) {
            return;
        }

        throw UnauthorizedAccessException::forPermission($permission);
    }

    protected function resolveContentLocale(Request $request): string
    {
        $codes = Language::allLocales()->pluck('code')->all();

        $locale = (string) $request->query('locale', '');

        if ($locale && in_array($locale, $codes, true)) {
            return $locale;
        }

        return $codes[0] ?? app()->getLocale();
    }

    protected function canDeleteRecord(ResourceDefinition $definition, mixed $record): bool
    {
        try {
            $definition->canDelete($record);

            return true;
        } catch (DeletionDeniedException) {
            return false;
        }
    }

    /** @return list<array{code: string, name: string, is_active: bool, is_default: bool}> */
    protected function resolveAvailableLanguages(): array
    {
        return array_values(array_map(
            fn (Language $l): array => [
                'code' => $l->code,
                'name' => $l->name,
                'is_active' => $l->is_active,
                'is_default' => $l->is_default,
            ],
            Language::allLocales()->all(),
        ));
    }
}
