<?php

declare(strict_types=1);

namespace ImovelZapAi\Authentication\Application\Actions;

use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;
use ImovelZapAi\Tenancy\Domain\Enums\TenantStatus;
use ImovelZapAi\Tenancy\Infrastructure\Persistence\Eloquent\TenantModel;
use ImovelZapAi\Tenancy\Support\TenantContext;
use Spatie\Permission\PermissionRegistrar;

final class LoginAction
{
    /** @var list<TenantStatus> */
    private const ALLOWED_STATUSES = [
        TenantStatus::Trial,
        TenantStatus::Active,
    ];

    /**
     * @return array{token: string, token_type: string, user: \Illuminate\Foundation\Auth\User}
     */
    public function execute(
        string $email,
        string $password,
        string $deviceName = 'api',
        ?string $tenantSlug = null,
    ): array {
        /** @var class-string<\Illuminate\Foundation\Auth\User> $userModel */
        $userModel = config('auth.providers.users.model');

        if ($tenantSlug !== null && trim($tenantSlug) !== '') {
            $tenant = TenantModel::query()->where('slug', $tenantSlug)->first();

            if ($tenant === null || ! in_array($tenant->status, self::ALLOWED_STATUSES, true)) {
                throw ValidationException::withMessages([
                    'email' => [__('auth.failed')],
                ]);
            }

            $user = $userModel::query()
                ->where('tenant_id', $tenant->id)
                ->whereRaw('lower(email) = ?', [strtolower(trim($email))])
                ->first();

            if (! $user instanceof \Illuminate\Database\Eloquent\Model || ! Hash::check($password, $user->password)) {
                throw ValidationException::withMessages([
                    'email' => [__('auth.failed')],
                ]);
            }
        } else {
            $user = null;
            $candidates = $userModel::query()
                ->whereRaw('lower(email) = ?', [strtolower(trim($email))])
                ->with('tenant')
                ->get();

            foreach ($candidates as $candidate) {
                $tenant = $candidate->tenant ?? null;
                if ($tenant === null || ! in_array($tenant->status, self::ALLOWED_STATUSES, true)) {
                    continue;
                }
                if (! Hash::check($password, (string) $candidate->password)) {
                    continue;
                }
                $user = $candidate;
                break;
            }

            if ($user === null) {
                throw ValidationException::withMessages([
                    'email' => [__('auth.failed')],
                ]);
            }
        }

        TenantContext::set((string) $user->tenant_id);
        app(PermissionRegistrar::class)->setPermissionsTeamId((string) $user->tenant_id);

        /** @var \App\Models\User $user */
        $token = $user->createToken($deviceName)->plainTextToken;

        return [
            'token' => $token,
            'token_type' => 'Bearer',
            'user' => $user,
        ];
    }
}
