Al-HUWAITI Shell
Al-huwaiti


Server : LiteSpeed
System : Linux server335.web-hosting.com 4.18.0-553.62.1.lve.el8.x86_64 #1 SMP Mon Jul 21 17:50:35 UTC 2025 x86_64
User : cardxfeb ( 2452)
PHP Version : 8.1.34
Disable Function : NONE
Directory :  /proc/thread-self/root/proc/self/root/home/cardxfeb/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : //proc/thread-self/root/proc/self/root/home/cardxfeb/.bash_history
                'messages'   => [['role' => 'user', 'content' => $prompt]],
            ]);

            if (!$response->ok()) {
                Log::error('[LlmAnalyzer] API error: ' . $response->status() . ' - ' . $response->body());
                return $this->fallbackResult($merged);
            }

            $text = $response->json('content.0.text', '');

            // Strip markdown code blocks if present
            $text = preg_replace('/^```(?:json)?\s*/m', '', $text);
            $text = preg_replace('/\s*```$/m', '', $text);
            $text = trim($text);

            $data = json_decode($text, true);

            if (json_last_error() !== JSON_ERROR_NONE) {
                Log::warning('[LlmAnalyzer] Invalid JSON from LLM: ' . substr($text, 0, 200));
                return $this->fallbackResult($merged);
            }

            // Sanitize template_id
            $data['template_id'] = max(1, min(24, (int)($data['template_id'] ?? 1)));

            // If no valid color from LLM, use detected brand color
            if (empty($data['color_primary']) || !preg_match('/^#[0-9a-fA-F]{3,6}$/', $data['color_primary'])) {
                $data['color_primary'] = $brandColors['theme_color']
                    ?? $brandColors['css_primary']
                    ?? '#2563EB';
            }

            return $data;

        } catch (\Exception $e) {
            Log::error('[LlmAnalyzer] Exception: ' . $e->getMessage());
            return $this->fallbackResult($merged);
        }
    }

    /**
     * Legacy single-source analyze (backward compatibility)
     */
    public function analyze(array $scrapedData, string $region = 'BR'): array
    {
        // Wrap single source as multi-source format
        $wrapped = [
            'social'    => [$scrapedData],
            'corporate' => [],
            'merged'    => [
                'name'         => $scrapedData['title']       ?? '',
                'bio_hint'     => $scrapedData['description'] ?? '',
                'brand_name'   => '',
                'brand_desc'   => '',
                'brand_colors' => [],
                'platforms'    => [$scrapedData['platform']   ?? 'website'],
                'sources'      => 1,
            ],
        ];
        return $this->analyzeMultiple($wrapped, $region);
    }

    private function fallbackResult(array $merged): array
    {
        $brandColor = $merged['brand_colors']['theme_color']
            ?? $merged['brand_colors']['css_primary']
            ?? '#2563EB';

        return [
            'name'              => $merged['name']       ?? 'Meu Carto Digital',
            'profession'        => '',
            'bio'               => $merged['bio_hint']   ?? '',
            'company'           => $merged['brand_name'] ?? '',
            'color_primary'     => $brandColor,
            'color_secondary'   => '#F59E0B',
            'template_id'       => 1,
            'links'             => [],
            'social_handles'    => [],
            'brand_personality' => 'profissional',
            'confidence'        => 'low',
        ];
    }
}
'''

with open(f"{base}/app/Services/LlmAnalyzerService.php", 'w') as f:
    f.write(llm)
print(f"UPGRADED: LlmAnalyzerService.php ({len(llm)} chars)")

# ============================================================
# 3. AiCardGeneratorService.php  use fetchMultiple + analyzeMultiple
# ============================================================
generator = r'''<?php

namespace App\Services;

use App\Models\Vcard;
use App\Models\User;
use Illuminate\Support\Facades\Log;

class AiCardGeneratorService
{
    public function __construct(
        protected SocialScraperService $scraper,
        protected LlmAnalyzerService   $llm
    ) {}

    /**
     * Full AI generation pipeline with MULTI-SOURCE support.
     * $sources can be a single URL string or an array of URLs.
     */
    public function generate(User $user, string|array $sources, Vcard $vcard): array
    {
        // Normalize to array
        if (is_string($sources)) {
            $sources = [$sources];
        }
        $sources = array_filter($sources, fn($s) => !empty(trim($s)));

        try {
            // Step 1: Fetch from ALL sources in parallel (sequential for shared hosting)
            Log::info("[AiCardGen] Fetching " . count($sources) . " sources for user#{$user->id}");
            $multiSourceData = $this->scraper->fetchMultiple($sources);

            $socialCount    = count($multiSourceData['social']    ?? []);
            $corporateCount = count($multiSourceData['corporate'] ?? []);
            Log::info("[AiCardGen] Fetched: {$socialCount} social, {$corporateCount} corporate sources");

            // Step 2: LLM multi-source analysis
            $region   = config('app.region', 'BR');
            $aiResult = $this->llm->analyzeMultiple($multiSourceData, $region);
            Log::info("[AiCardGen] LLM result: template_id={$aiResult['template_id']}, confidence={$aiResult['confidence']}");

            // Step 3: Apply to VCard
            $updateData = [
                'ai_status'   => 'completed',
                'ai_data'     => json_encode($aiResult, JSON_UNESCAPED_UNICODE),
                'template_id' => $aiResult['template_id'],
            ];

            // Only fill fields if VCard doesn't already have them
            if (empty($vcard->name) && !empty($aiResult['name'])) {
                $updateData['name'] = $aiResult['name'];
            }
            if (empty($vcard->description) && !empty($aiResult['bio'])) {
                $updateData['description'] = $aiResult['bio'];
            }
            if (empty($vcard->occupation) && !empty($aiResult['profession'])) {
                $updateData['occupation'] = $aiResult['profession'];
            }
            if (empty($vcard->company) && !empty($aiResult['company'])) {
                $updateData['company'] = $aiResult['company'];
            }

            $vcard->update($updateData);

            return [
                'success'        => true,
                'vcard_id'       => $vcard->id,
                'template_id'    => $aiResult['template_id'],
                'completion_pct' => 90,
                'sources_used'   => count($sources),
                'confidence'     => $aiResult['confidence'] ?? 'medium',
                'ai_result'      => $aiResult,
            ];

        } catch (\Exception $e) {
            Log::error("[AiCardGen] Failed for user#{$user->id}: " . $e->getMessage());
            $vcard->update(['ai_status' => 'failed']);
            return ['success' => false, 'vcard_id' => $vcard->id, 'error' => $e->getMessage()];
        }
    }
}
'''

with open(f"{base}/app/Services/AiCardGeneratorService.php", 'w') as f:
    f.write(generator)
print(f"UPGRADED: AiCardGeneratorService.php ({len(generator)} chars)")

# ============================================================
# 4. OnboardingController.php  sources[] array support
# ============================================================
onboarding = r'''<?php

namespace App\Http\Controllers;

use App\Jobs\GenerateAiCardJob;
use App\Models\Vcard;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Rule;

class OnboardingController extends Controller
{
    /** Show the onboarding form */
    public function create()
    {
        return view('vcard.onboarding');
    }

    /**
     * Store: accept 15 source URLs, create VCard skeleton, dispatch AI job.
     * Input: sources[] array (or legacy social_url string)
     */
    public function store(Request $request): \Illuminate\Http\RedirectResponse
    {
        // Support both legacy single URL and new multi-source array
        if ($request->has('social_url') && !$request->has('sources')) {
            $request->merge(['sources' => [$request->input('social_url')]]);
        }

        $request->validate([
            'sources'   => ['required', 'array', 'min:1', 'max:5'],
            'sources.*' => ['required', 'url', 'max:500', 'distinct'],
        ], [
            'sources.required'   => 'Fornea pelo menos uma URL de rede social ou site.',
            'sources.max'        => 'Pode fornecer no mximo 5 fontes.',
            'sources.*.url'      => 'Uma das URLs fornecidas no  vlida.',
            'sources.*.distinct' => 'No repita URLs.',
        ]);

        $user    = Auth::user();
        $sources = array_filter($request->sources, fn($s) => !empty(trim($s)));

        // Determine primary URL for backward compatibility
        $primaryUrl = $sources[0] ?? '';

        // Create VCard skeleton
        $vcard = Vcard::create([
            'user_id'          => $user->id,
            'tenant_id'        => $user->tenant_id ?? null,
            'name'             => $user->name,
            'url_alias'        => 'card-' . uniqid(),
            'status'           => 'pending_payment',
            'ai_status'        => 'pending',
            'ai_social_url'    => json_encode(array_values($sources), JSON_UNESCAPED_SLASHES),
            'payment_deadline' => now()->addHours(24),
            'template_id'      => 1,
        ]);

        Log::info("[Onboarding] VCard#{$vcard->id} created. Sources: " . implode(', ', $sources));

        // Dispatch AI job with full sources array
        GenerateAiCardJob::dispatch($user, $sources, $vcard->id)
            ->onQueue('ai-generation');

        return redirect()->route('vcard.processing', ['vcard' => $vcard->id])
            ->with('message', count($sources) > 1
                ? 'A IA est a analisar ' . count($sources) . ' fontes para criar o seu carto...'
                : 'A IA est a preparar o seu carto...'
            );
    }

    /** Show processing screen */
    public function processing(Vcard $vcard)
    {
        if ($vcard->user_id !== Auth::id()) {
            abort(403);
        }
        return view('vcard.processing', compact('vcard'));
    }

    /** API: Poll AI status */
    public function aiStatus(Vcard $vcard): JsonResponse
    {
        if ($vcard->user_id !== Auth::id()) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        $aiData = null;
        if ($vcard->ai_status === 'completed' && $vcard->ai_data) {
            $decoded = json_decode($vcard->ai_data, true);
            $aiData  = [
                'template_id'       => $decoded['template_id']    ?? null,
                'color_primary'     => $decoded['color_primary']  ?? null,
                'confidence'        => $decoded['confidence']      ?? null,
                'brand_personality' => $decoded['brand_personality'] ?? null,
            ];
        }

        return response()->json([
            'vcard_id'     => $vcard->id,
            'ai_status'    => $vcard->ai_status,
            'template_id'  => $vcard->template_id,
            'ai_data'      => $aiData,
            'redirect_url' => $vcard->ai_status === 'completed'
                ? route('user.vcard.edit', $vcard->id)
                : null,
        ]);
    }
}
'''

with open(f"{base}/app/Http/Controllers/OnboardingController.php", 'w') as f:
    f.write(onboarding)
print(f"UPGRADED: OnboardingController.php ({len(onboarding)} chars)")

# ============================================================
# 5. GenerateAiCardJob.php  support array sources
# ============================================================
job = r'''<?php

namespace App\Jobs;

use App\Models\Vcard;
use App\Models\User;
use App\Services\AiCardGeneratorService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;

class GenerateAiCardJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public int $tries   = 3;
    public int $timeout = 180; // 3 min  multi-source takes longer
    public int $backoff = 30;

    public function __construct(
        public User         $user,
        public string|array $sources,  // single URL or array of URLs
        public int          $vcardId
    ) {}

    public function handle(AiCardGeneratorService $aiService): void
    {
        $vcard = Vcard::findOrFail($this->vcardId);
        $vcard->update(['ai_status' => 'processing']);

        $sourcesCount = is_array($this->sources) ? count($this->sources) : 1;
        Log::info("[GenerateAiCardJob] Starting: user#{$this->user->id}, vcard#{$this->vcardId}, {$sourcesCount} source(s)");

        $result = $aiService->generate($this->user, $this->sources, $vcard);

        if ($result['success']) {
            Log::info("[GenerateAiCardJob] Done: template_id={$result['template_id']}, confidence={$result['confidence']}");
        } else {
            Log::error("[GenerateAiCardJob] Failed: " . ($result['error'] ?? 'unknown'));
            $this->fail(new \Exception($result['error'] ?? 'AI generation failed'));
        }
    }

    public function failed(\Throwable $exception): void
    {
        Vcard::find($this->vcardId)?->update(['ai_status' => 'failed']);
        Log::error("[GenerateAiCardJob] Permanently failed: " . $exception->getMessage());
    }
}
'''

with open(f"{base}/app/Jobs/GenerateAiCardJob.php", 'w') as f:
    f.write(job)
print(f"UPGRADED: GenerateAiCardJob.php ({len(job)} chars)")

print("\nAll service upgrades complete!")
PYEOF

python3 /tmp/phase33_llm_onboarding.py
cat > /tmp/fix_csrf.py << 'PYEOF'
import os, re

base = os.path.expanduser('~/public_html')

# Find VerifyCsrfToken middleware
csrf_paths = [
    f'{base}/app/Http/Middleware/VerifyCsrfToken.php',
    f'{base}/bootstrap/app.php',
]

for p in csrf_paths:
    if os.path.exists(p):
        with open(p, 'r') as f:
            content = f.read()
        print(f'Found: {p}')
        print(content[:600])
        print('---')

PYEOF

python3 /tmp/fix_csrf.py
grep -n 'csrf\|VerifyCsrf\|webhook\|except' bootstrap/app.php app/Http/Middleware/*.php 2>/dev/null | head -30
cat app/Http/Middleware/VerifyCsrfToken.php
python3 -c "
import os
p = os.path.expanduser('~/public_html/app/Http/Middleware/VerifyCsrfToken.php')
with open(p,'r') as f: c = f.read()
if 'webhooks/brasil' not in c:
    old = \"'/phonepe-Product-response'\"
    new = old + \",\n        // === CARD AO SEGUNDO CONTROL webhooks ===\n        '/api/webhooks/brasil',\n        '/api/webhooks/portugal',\n        '/webhooks/brasil',\n        '/webhooks/portugal'\"
    c = c.replace(old, new, 1)
    with open(p,'w') as f: f.write(c)
    print('CSRF exceptions added')
else:
    print('Already added')
"
php artisan config:clear && php artisan cache:clear && php artisan route:clear && php artisan view:clear && echo 'CACHE CLEARED'
python3 -c "
import re
p = '/home/cardxfeb/public_html/.env'
with open(p,'r') as f: c = f.read()
new_key = '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'
c2 = re.sub(r'CLAUDE_API_KEY=.*', 'CLAUDE_API_KEY=' + new_key, c)
if c2 != c:
    with open(p,'w') as f: f.write(c2)
    print('KEY UPDATED OK')
else:
    print('KEY NOT FOUND - check .env')
"
php artisan config:clear && echo 'CONFIG CLEARED'
cd /home/cardxfeb/public_html && php artisan tinker --no-interaction 2>&1 &
cd /home/cardxfeb/public_html && php artisan tinker
python3 << 'PYEOF'
import re

# 1. Create HTTP validation file
token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJkb21haW4iOiJjYXJkLmFvc2VndW5kby5jb20uYnIiLCJleHAiOjE3Nzc2ODAwMDB9.nMfClhVIR-5_MO0NCaFuKzb-b12j2-yH2IaCtV2Qhnk'
with open('/home/cardxfeb/public_html/simpledcver.txt', 'w') as f:
    f.write(token)
print('1. simpledcver.txt CRIADO OK')

# 2. Update ASAAS_WEBHOOK_TOKEN in .env
env_path = '/home/cardxfeb/public_html/.env'
with open(env_path, 'r') as f:
    c = f.read()
wt = 'whsec_W8UvAs029jxRsq1LheBK3Z99FHE8M9AVapBRGIq4bFI'
c2 = re.sub(r'ASAAS_WEBHOOK_TOKEN=.*', 'ASAAS_WEBHOOK_TOKEN=' + wt, c)
if c2 != c:
    with open(env_path, 'w') as f:
        f.write(c2)
    print('2. ASAAS_WEBHOOK_TOKEN ATUALIZADO OK')
else:
    print('2. ASAAS_WEBHOOK_TOKEN nao encontrado - adicionando')
    with open(env_path, 'a') as f:
        f.write('\nASSAAS_WEBHOOK_TOKEN=' + wt + '\n')
    print('2. ASAAS_WEBHOOK_TOKEN ADICIONADO OK')

# 3. Verify file is accessible
import os
size = os.path.getsize('/home/cardxfeb/public_html/simpledcver.txt')
print(f'3. Arquivo simpledcver.txt: {size} bytes')
PYEOF

curl -s https://cardfyz.com/simpledcver.txt | head -5
head -20 /home/cardxfeb/public_html/.htaccess
python3 << 'PYEOF'
# Add exception for simpledcver.txt in .htaccess
htpath = '/home/cardxfeb/public_html/.htaccess'
with open(htpath, 'r') as f:
    c = f.read()

exception = '\n    # Domain Validation File - do not remove\n    RewriteCond %{REQUEST_URI} !^/simpledcver\.txt$\n'

# Insert before the main Laravel rewrite rule
if 'simpledcver' not in c:
    c = c.replace('    RewriteCond %{REQUEST_FILENAME} !-d', exception + '    RewriteCond %{REQUEST_FILENAME} !-d')
    with open(htpath, 'w') as f:
        f.write(c)
    print('HTACCESS UPDATED - exception added')
else:
    print('ALREADY HAS EXCEPTION')
PYEOF

curl -s https://cardfyz.com/simpledcver.txt
python3 << 'PYEOF'
htpath = '/home/cardxfeb/public_html/.htaccess'
with open(htpath, 'r') as f:
    c = f.read()
# Add rule at the very beginning to serve simpledcver.txt directly
rule = 'RewriteEngine On\nRewriteRule ^simpledcver\.txt$ simpledcver.txt [L]\n\n'
if 'simpledcver.txt [L]' not in c:
    c = rule + c
    with open(htpath, 'w') as f:
        f.write(c)
    print('RULE ADDED AT TOP')
else:
    print('ALREADY EXISTS')
PYEOF

curl -s https://cardfyz.com/simpledcver.txt | head -3
tail -n 100 ~/public_html/storage/logs/laravel.log
cat ~/public_html/app/Http/Middleware/DetectRegion.php
head -n 30 ~/public_html/app/Http/Middleware/DetectRegion.php
sed -n '1,25p' ~/public_html/app/Http/Middleware/DetectRegion.php
sed -n '14,80p' ~/public_html/app/Http/Middleware/DetectRegion.php
sed -n '14,50p' ~/public_html/app/Http/Middleware/DetectRegion.php | cat -n
sed -i "s/'payment_gateway' => env('GATEWAY_BR', 'manual'),/'payment_gateway' => 'stripe_br',/g" ~/public_html/app/Http/Middleware/DetectRegion.php
grep -n 'env(' ~/public_html/app/Http/Middleware/DetectRegion.php
python3 -c "content = open('/home/cardxfeb/public_html/app/Http/Middleware/DetectRegion.php').read(); content = content.replace(\"'payment_gateway' => env('GATEWAY_BR', 'manual'),\", \"'payment_gateway' => 'stripe_br',\"); open('/home/cardxfeb/public_html/app/Http/Middleware/DetectRegion.php', 'w').write(content); print('Corrigido''')"
grep -n 'env(' ~/public_html/app/Http/Middleware/DetectRegion.php
sed -n '28,32p' ~/public_html/app/Http/Middleware/DetectRegion.php
php -l ~/public_html/app/Http/Middleware/DetectRegion.php
cd ~/public_html && php artisan config:clear && php artisan cache:clear && php artisan route:clear && php artisan view:clear
echo 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJkb21haW4iOiJjYXJkLmFvc2VndW5kby5wdCIsImFjY6MTc3NzY4MDAwMH0.cgNI_luwIx2vnV_uYufiQ-kcxJtE1f2KjDc9tjVFN5M' > ~/public_html/public/simpledcver.txt && echo 'Arquivo criado!'
host card.aosegundo.pt
host card.aosegundo.com.br && host aosegundo.pt
cd ~/public_html && php artisan tinker --execute="Mail::raw('Teste de e-mail do servidor CARDFYZ - OK', function(\$m) { \$m->to('geral@cardfyz.com')->subject('Teste de Envio - Card Ao Segundo'); });"
grep -E 'MAIL_|SMTP' ~/public_html/.env
python3 -c "content = open('/home/cardxfeb/public_html/.env').read(); content = content.replace('MAIL_HOST=mail.cardfyz.com', 'MAIL_HOST=server335.web-hosting.com'); open('/home/cardxfeb/public_html/.env', 'w').write(content); print('MAIL_HOST corrigido''')"
php artisan config:clear && php artisan tinker --execute="Mail::raw('Teste de e-mail do servidor CARDFYZ - OK', function(\$m) { \$m->to('geral@cardfyz.com')->subject('Teste de Envio - Card Ao Segundo'); });"
grep 'MAIL_HOST' ~/public_html/.env
cd ~/public_html && php artisan tinker --execute="Mail::raw('Teste CARDFYZ', function(\$m) { \$m->to('geral@cardfyz.com')->subject('Teste Cardfyz 2026'); }); echo 'OK';"
tail -n 80 ~/public_html/storage/logs/laravel.log | grep -A 20 'local.ERROR'
tail -n 50 ~/public_html/storage/logs/laravel.log
tail -n 200 ~/public_html/storage/logs/laravel.log | grep -B2 'sadmin\|admin\|ERROR' | head -n 60
cd ~/public_html && php artisan migrate:status 2>&1 | tail -n 30
php artisan tinker --execute="echo DB::select('SHOW COLUMNS FROM vcards LIKE \"deleted_at\"') ? 'Coluna existe' : 'Coluna NAO existe';"
php artisan make:migration add_soft_deletes_to_vcards_table --table=vcards
cat ~/public_html/database/migrations/2026_04_25_213715_add_soft_deletes_to_vcards_table.php
python3 << 'EOF'
content = open('/home/cardxfeb/public_html/database/migrations/2026_04_25_213715_add_soft_deletes_to_vcards_table.php').read()
content = content.replace(
    "Schema::table('vcards', function (Blueprint $table) {\n            //\n        });",
    "Schema::table('vcards', function (Blueprint $table) {\n            $table->softDeletes();\n        });",
    1
)
content = content.replace(
    "Schema::table('vcards', function (Blueprint $table) {\n            //\n        });",
    "Schema::table('vcards', function (Blueprint $table) {\n            $table->dropSoftDeletes();\n        });",
    1
)
open('/home/cardxfeb/public_html/database/migrations/2026_04_25_213715_add_soft_deletes_to_vcards_table.php', 'w').write(content)
print('Migration atualizada!')
EOF

cat ~/public_html/database/migrations/2026_04_25_213715_add_soft_deletes_to_vcards_table.php | grep -A5 'function up\|function down'
php artisan migrate --force 2>&1
ls -la ~/public_html/storage/framework/sessions/ | head -5 && stat -c '%a %n' ~/public_html/storage/framework/sessions/
cat ~/public_html/app/Http/Middleware/DetectRegion.php
sed -n '38,80p' ~/public_html/app/Http/Middleware/DetectRegion.php
sed -n '37,62p' ~/public_html/app/Http/Middleware/DetectRegion.php
wc -l ~/public_html/app/Http/Middleware/DetectRegion.php
python3 << 'PYEOF'
new_content = '''<?php

namespace App\\Http\\Middleware;

use Closure;
use Illuminate\\Http\\Request;
use Symfony\\Component\\HttpFoundation\\Response;

class DetectRegion
{
    /**
     * Mapa de dominios para configuracoes regionais
     * CARD AO SEGUNDO CONTROL - Multi-Dominio
     */
    protected array $regions = [
        \'card.aosegundo.pt\' => [
            \'currency\'         => \'EUR\',
            \'currency_symbol\'  => \'\',
            \'locale\'           => \'pt_PT\',
            \'country\'          => \'PT\',
            \'payment_gateway\'  => \'ifthen\',
            \'stripe_key\'       => \'STRIPE_KEY_PT\',
            \'stripe_secret\'    => \'STRIPE_SECRET_PT\',
            \'flag\'             => \'PT\',
            \'name\'             => \'Portugal\',
        ],
        \'card.aosegundo.com.br\' => [
            \'currency\'         => \'BRL\',
            \'currency_symbol\'  => \'R$\',
            \'locale\'           => \'pt_BR\',
            \'country\'          => \'BR\',
            \'payment_gateway\'  => \'asaas\',
            \'stripe_key\'       => \'STRIPE_KEY_BR\',
            \'stripe_secret\'    => \'STRIPE_SECRET_BR\',
            \'flag\'             => \'BR\',
            \'name\'             => \'Brasil\',
        ],
        \'cardfyz.com\' => [
            \'currency\'         => \'EUR\',
            \'currency_symbol\'  => \'\',
            \'locale\'           => \'pt_BR\',
            \'country\'          => \'BR\',
            \'payment_gateway\'  => \'stripe_br\',
            \'stripe_key\'       => \'STRIPE_KEY\',
            \'stripe_secret\'    => \'STRIPE_SECRET\',
            \'flag\'             => \'BR\',
            \'name\'             => \'Card Ao Segundo (legado)\',
        ],
    ];

    public function handle(Request $request, Closure $next): Response
    {
        $host   = $request->getHost();
        $region = $this->regions[$host] ?? $this->regions[\'cardfyz.com\'];

        // Determinar gateway activo baseado no .env (dinamico - seguro dentro do handle)
        if ($host === \'card.aosegundo.pt\') {
            $activeGateway = env(\'GATEWAY_PT\', $region[\'payment_gateway\']);
        } elseif ($host === \'card.aosegundo.com.br\') {
            $activeGateway = env(\'GATEWAY_BR\', $region[\'payment_gateway\']);
        } else {
            $activeGateway = env(\'GATEWAY_BR\', $region[\'payment_gateway\']);
        }

        // Injectar configuracoes regionais em runtime
        config([
            \'app.currency\'         => $region[\'currency\'],
            \'app.currency_symbol\'  => $region[\'currency_symbol\'],
            \'app.locale\'           => $region[\'locale\'],
            \'app.country\'          => $region[\'country\'],
            \'app.payment_gateway\'  => $activeGateway,
            \'app.region_flag\'      => $region[\'flag\'],
            \'app.region_name\'      => $region[\'name\'],
            \'app.url\'              => \'https://\' . $host,
        ]);

        // Partilhar com todas as views Blade
        view()->share(\'appRegion\', $region);
        view()->share(\'appCurrency\', $region[\'currency\']);
        view()->share(\'appCountry\', $region[\'country\']);
        view()->share(\'currentDomain\', $host);
        view()->share(\'activeGateway\', $activeGateway);

        return $next($request);
    }
}
'''
open('/home/cardxfeb/public_html/app/Http/Middleware/DetectRegion.php', 'w').write(new_content)
print('DetectRegion.php reescrito com sucesso!')
PYEOF

php -l ~/public_html/app/Http/Middleware/DetectRegion.php && php artisan config:clear && php artisan cache:clear && php artisan route:clear && php artisan view:clear
find ~ -name 'artisan' 2>/dev/null | head -20
ls /home/cardxfeb/public_html/app/Http/Controllers/ | grep -i 'front\|subscription\|home'
grep -n 'plan\|Plan\|currency\|currency_id' /home/cardxfeb/public_html/app/Http/Controllers/HomeController.php | head -40
grep -n 'choosePayment\|choose_payment\|paymentType\|currency\|BRL\|EUR' /home/cardxfeb/public_html/app/Http/Controllers/SubscriptionController.php | head -30
cd /home/cardxfeb/public_html && cat .env | grep -i 'app_name\|app_url\|app_env' | head -5
grep 'ASAAS' .env
sed -i 's/ASAAS_API_KEY=CONFIGURE_ME/ASAAS_API_KEY=597b4340-f667-41f2-940c-90f4c8cc1f43/' .env && sed -i 's/ASAAS_SANDBOX=true/ASAAS_SANDBOX=false/' .env && grep 'ASAAS' .env
find . -name '*saa*' -o -name '*Asaas*' 2>/dev/null | grep -v vendor | grep -v node_modules
grep -r 'asaas\|Asaas' app/Http/Controllers/ --include='*.php' -l 2>/dev/null
cat app/Http/Controllers/Webhooks/BrasilWebhookController.php
head -80 app/Http/Controllers/Webhooks/BrasilWebhookController.php
ls app/Http/Controllers/ && echo '---' && ls app/Http/Controllers/Webhooks/ 2>/dev/null
python3 -c "
conteudo = '''<?php
namespace App\\Http\\Controllers;

use App\\Models\\Plan;
use App\\Models\\User;
use Illuminate\\Http\\Request;
use Illuminate\\Support\\Facades\\Http;
use Illuminate\\Support\\Facades\\Auth;
use Illuminate\\Support\\Facades\\Log;

class AsaasController extends Controller
{
    private string \$apiKey;
    private string \$baseUrl;

    public function __construct()
    {
        \$this->apiKey  = env(\"ASAAS_API_KEY\");
        \$this->baseUrl = env(\"ASAAS_BASE_URL\", \"https://api.asaas.com/v3\");
    }

    public function showCheckout(int \$planId)
    {
        \$plan = Plan::with(\"currency\")->findOrFail(\$planId);
        if (\$plan->currency->currency_code !== \"BRL\") {
            abort(403, \"Plano nao disponivel para esta regiao.\");
        }
        return view(\"asaas.checkout\", compact(\"plan\"));
    }

    public function processPayment(Request \$request, int \$planId)
    {
        \$request->validate([
            \"cpf_cnpj\" => [\"required\", \"string\", \"min:11\", \"max:18\"],
            \"name\"     => [\"required\", \"string\"],
            \"email\"    => [\"required\", \"email\"],
        ]);
        \$plan = Plan::with(\"currency\")->findOrFail(\$planId);
        \$cpf  = preg_replace(\"/\\D/\", \"\", \$request->cpf_cnpj);
        \$customer = \$this->createOrFindCustomer(\$cpf, \$request->name, \$request->email);
            return back()->withErrors([\"asaas\" => \"Erro cliente Asaas: \".json_encode(\$customer[\"errors\"] ?? [])]);
        }
        \$userId = Auth::id();
        \$charge = \$this->createPixCharge(\$customer[\"id\"], \$plan->price, \"Plano {\$plan->name}\", \$planId, \$userId);
            return back()->withErrors([\"asaas\" => \"Erro cobranca: \".json_encode(\$charge[\"errors\"] ?? [])]);
        }
        \$pixData = \$this->getPixQrCode(\$charge[\"id\"]);
        return view(\"asaas.pix\", compact(\"plan\", \"charge\", \"pixData\"));
    }

    private function createOrFindCustomer(string \$cpfCnpj, string \$name, string \$email): array
    {
        \$search = Http::withHeaders([\"access_token\" => \$this->apiKey])
            ->get(\"\$this->baseUrl/customers\", [\"cpfCnpj\" => \$cpfCnpj]);
        if (\$search->ok() && \$search->json(\"totalCount\") > 0) {
            return \$search->json(\"data.0\");
        }
        return Http::withHeaders([\"access_token\" => \$this->apiKey])
            ->post(\"\$this->baseUrl/customers\", [\"name\" => \$name, \"email\" => \$email, \"cpfCnpj\" => \$cpfCnpj])
            ->json();
    }

    private function createPixCharge(string \$customerId, float \$value, string \$description, int \$planId, int \$userId): array
    {
        return Http::withHeaders([\"access_token\" => \$this->apiKey])
            ->post(\"\$this->baseUrl/payments\", [
                \"customer\"          => \$customerId,
                \"billingType\"       => \"PIX\",
                \"value\"             => \$value,
                \"dueDate\"           => now()->addDay()->format(\"Y-m-d\"),
                \"description\"       => \$description,
                \"externalReference\" => \"plan_{\$planId}_user_{\$userId}\",
            ])->json();
    }

    private function getPixQrCode(string \$chargeId): array
    {
        return Http::withHeaders([\"access_token\" => \$this->apiKey])
            ->get(\"\$this->baseUrl/payments/{\$chargeId}/pixQrCode\")
            ->json();
    }
}
'''
with open('app/Http/Controllers/AsaasController.php', 'w') as f:
    f.write(conteudo)
print('AsaasController criado com sucesso')
"
cat > /tmp/create_asaas.py << 'PYEOF'
import os

content = """<?php
namespace App\\Http\\Controllers;

use App\\Models\\Plan;
use Illuminate\\Http\\Request;
use Illuminate\\Support\\Facades\\Http;
use Illuminate\\Support\\Facades\\Auth;
use Illuminate\\Support\\Facades\\Log;

class AsaasController extends Controller
{
    private $apiKey;
    private $baseUrl;

    public function __construct()
    {
        $this->apiKey  = env('ASAAS_API_KEY');
        $this->baseUrl = env('ASAAS_BASE_URL', 'https://api.asaas.com/v3');
    }

    public function showCheckout($planId)
    {
        $plan = Plan::with('currency')->findOrFail($planId);
        abort_unless($plan->currency->currency_code === 'BRL', 403);
        return view('asaas.checkout', compact('plan'));
    }

    public function processPayment(Request $request, $planId)
    {
        $request->validate([
            'cpf_cnpj' => ['required','string','min:11','max:18'],
            'name'     => ['required','string'],
            'email'    => ['required','email'],
        ]);
        $plan     = Plan::with('currency')->findOrFail($planId);
        $cpf      = preg_replace('/[^0-9]/', '', $request->cpf_cnpj);
        $customer = $this->createOrFindCustomer($cpf, $request->name, $request->email);
        if (!$customer || isset($customer['errors'])) {
            return back()->withErrors(['asaas' => 'Erro cliente: '.json_encode($customer['errors'] ?? [])]);
        }
        $userId = Auth::id();
        $charge = $this->createPixCharge($customer['id'], $plan->price, 'Plano '.$plan->name, $planId, $userId);
        if (!$charge || isset($charge['errors'])) {
            return back()->withErrors(['asaas' => 'Erro cobranca: '.json_encode($charge['errors'] ?? [])]);
        }
        $pixData = $this->getPixQrCode($charge['id']);
        return view('asaas.pix', compact('plan', 'charge', 'pixData'));
    }

    private function createOrFindCustomer($cpfCnpj, $name, $email)
    {
        $search = Http::withHeaders(['access_token' => $this->apiKey])
            ->get($this->baseUrl.'/customers', ['cpfCnpj' => $cpfCnpj]);
        if ($search->ok() && $search->json('totalCount') > 0) {
            return $search->json('data')[0];
        }
        return Http::withHeaders(['access_token' => $this->apiKey])
            ->post($this->baseUrl.'/customers', ['name' => $name, 'email' => $email, 'cpfCnpj' => $cpfCnpj])
            ->json();
    }

    private function createPixCharge($customerId, $value, $description, $planId, $userId)
    {
        return Http::withHeaders(['access_token' => $this->apiKey])
            ->post($this->baseUrl.'/payments', [
                'customer'          => $customerId,
                'billingType'       => 'PIX',
                'value'             => $value,
                'dueDate'           => date('Y-m-d', strtotime('+1 day')),
                'description'       => $description,
                'externalReference' => 'plan_'.$planId.'_user_'.$userId,
            ])->json();
    }

    private function getPixQrCode($chargeId)
    {
        return Http::withHeaders(['access_token' => $this->apiKey])
            ->get($this->baseUrl.'/payments/'.$chargeId.'/pixQrCode')
            ->json();
    }
}
"""

with open('/home/cardxfeb/public_html/app/Http/Controllers/AsaasController.php', 'w') as f:
    f.write(content)
print('OK: AsaasController.php criado')
PYEOF

python3 /tmp/create_asaas.py
mkdir -p resources/views/asaas && ls resources/views/ | grep asaas
ls resources/views/layouts/ | head -5
cat > /tmp/create_views.py << 'PYEOF'
checkout = """@extends('layouts.app')
@section('title', 'Checkout - Plano Brasil')
@section('content')
<div class="container mt-5">
    <div class="row justify-content-center">
        <div class="col-md-6">
            <div class="card shadow">
                <div class="card-header bg-primary text-white">
                    <h4 class="mb-0">Assinar {{ $plan->name }}</h4>
                </div>
                <div class="card-body">
                    <p class="lead">Valor: <strong>R$ {{ number_format($plan->price, 2, ',', '.') }}/ms</strong></p>
                    <hr>
                    <form method="POST" action="{{ route('asaas.checkout.process', $plan->id) }}">
                        @csrf
                        <div class="mb-3">
                            <label class="form-label">Nome Completo *</label>
                            <input type="text" name="name" class="form-control @error('name') is-invalid @enderror" value="{{ auth()->user()->name ?? '' }}" required>
                            @error('name') <div class="invalid-feedback">{{ $message }}</div> @enderror
                        </div>
                        <div class="mb-3">
                            <label class="form-label">E-mail *</label>
                            <input type="email" name="email" class="form-control @error('email') is-invalid @enderror" value="{{ auth()->user()->email ?? '' }}" required>
                            @error('email') <div class="invalid-feedback">{{ $message }}</div> @enderror
                        </div>
                        <div class="mb-3">
                            <label class="form-label">CPF ou CNPJ * <small class="text-muted">(obrigatrio para Pix)</small></label>
                            <input type="text" name="cpf_cnpj" class="form-control @error('cpf_cnpj') is-invalid @enderror" placeholder="000.000.000-00" maxlength="18" required>
                            @error('cpf_cnpj') <div class="invalid-feedback">{{ $message }}</div> @enderror
                        </div>
                        @if($errors->has('asaas'))
                            <div class="alert alert-danger">{{ $errors->first('asaas') }}</div>
                        @endif
                        <div class="d-grid">
                            <button type="submit" class="btn btn-success btn-lg">Gerar QR Code Pix</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection
"""

pix = """@extends('layouts.app')
@section('title', 'Pague via Pix')
@section('content')
<div class="container mt-5">
    <div class="row justify-content-center">
        <div class="col-md-6 text-center">
            <div class="card shadow">
                <div class="card-header bg-success text-white">
                    <h4 class="mb-0">Pague via Pix</h4>
                </div>
                <div class="card-body">
                    <p>Plano: <strong>{{ $plan->name }}</strong></p>
                    <p>Valor: <strong>R$ {{ number_format($plan->price, 2, ',', '.') }}</strong></p>
                    @if(isset($pixData['encodedImage']))
                        <img src="data:image/png;base64,{{ $pixData['encodedImage'] }}" alt="QR Code Pix" class="img-fluid" style="max-width:280px">
                        <div class="mt-3">
                            <label class="form-label"><small>Cdigo Copia e Cola:</small></label>
                            <textarea class="form-control" rows="3" onclick="this.select()" readonly>{{ $pixData['payload'] ?? '' }}</textarea>
                        </div>
                    @else
                        <div class="alert alert-warning">QR Code no disponvel. Tente novamente.</div>
                    @endif
                    <p class="mt-3 text-muted"><small>Aps o pagamento, seu plano ser ativado automaticamente.</small></p>
                    <a href="{{ route('admin.dashboard') }}" class="btn btn-outline-primary mt-2">Ir para o Painel</a>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection
"""

with open('/home/cardxfeb/public_html/resources/views/asaas/checkout.blade.php', 'w') as f:
    f.write(checkout)
print('OK: checkout.blade.php criado')

with open('/home/cardxfeb/public_html/resources/views/asaas/pix.blade.php', 'w') as f:
    f.write(pix)
print('OK: pix.blade.php criado')
PYEOF

python3 /tmp/create_views.py
tail -20 routes/web.php
grep -n 'auth\|middleware.*auth\|role' routes/web.php | tail -10
wc -l routes/web.php
cat >> routes/web.php << 'ROUTESEOF'

//  Asaas Checkout (Brasil/BRL) 
use App\Http\Controllers\AsaasController;
Route::middleware(['auth', 'valid.user', 'role:admin'])->group(function () {
    Route::get('/admin/asaas/checkout/{planId}',  [AsaasController::class, 'showCheckout'])->name('asaas.checkout.show');
    Route::post('/admin/asaas/checkout/{planId}', [AsaasController::class, 'processPayment'])->name('asaas.checkout.process');
});
ROUTESEOF

cat app/Http/Middleware/VerifyCsrfToken.php
sed -n '45,55p' app/Http/Controllers/HomeController.php
cp app/Http/Controllers/HomeController.php app/Http/Controllers/HomeController.php.bak && echo 'backup criado'
cat > /tmp/patch_home.py << 'PYEOF'
with open('app/Http/Controllers/HomeController.php', 'r') as f:
    content = f.read()

old = """        $plans = Plan::with(['currency', 'planFeature', 'hasZeroPlan', 'planCustomFields'])->whereIsDefault(Plan::IS_DEACTIVE)->whereStatus(Plan::IS_ACTIVE)->get();"""

new = """        // Isolamento regional de planos por hostname
        $host = request()->getHost();
        $currencyCode = 'EUR'; // default Europa
        if (str_contains($host, '.com.br')) { $currencyCode = 'BRL'; }
        elseif (str_contains($host, '.pt'))  { $currencyCode = 'EUR'; }

        $plans = Plan::with(['currency', 'planFeature', 'hasZeroPlan', 'planCustomFields'])
            ->whereIsDefault(Plan::IS_DEACTIVE)
            ->whereStatus(Plan::IS_ACTIVE)
            ->whereHas('currency', function ($q) use ($currencyCode) {
                $q->where('currency_code', $currencyCode);
            })
            ->get();"""

if old in content:
    content = content.replace(old, new)
    with open('app/Http/Controllers/HomeController.php', 'w') as f:
        f.write(content)
    print('OK: HomeController.php atualizado com filtro regional')
else:
    print('AVISO: Linha nao encontrada exatamente - verificar manualmente')
    print('Trecho atual (linha 49):')
    lines = content.split(chr(10))
    for i, l in enumerate(lines[47:52], 48):
        print(str(i) + ': ' + l)
PYEOF

python3 /tmp/patch_home.py
sed -n '83,115p' app/Http/Controllers/SubscriptionController.php
cp app/Http/Controllers/SubscriptionController.php app/Http/Controllers/SubscriptionController.php.bak && echo 'backup ok'
cat > /tmp/patch_sub.py << 'PYEOF'
with open('app/Http/Controllers/SubscriptionController.php', 'r') as f:
    content = f.read()

old = "        $subscriptionsPricingPlan = Plan::findOrFail($planId);"

new = "        $subscriptionsPricingPlan = Plan::with('currency')->findOrFail($planId);"
        "\n        // Redirecionar planos BRL para o checkout Asaas"
        "\n        if ($subscriptionsPricingPlan->currency && $subscriptionsPricingPlan->currency->currency_code === 'BRL') {"
        "\n            return redirect()->route('asaas.checkout.show', $planId);"
        "\n        }"

if old in content:
    content = content.replace(old, new)
    with open('app/Http/Controllers/SubscriptionController.php', 'w') as f:
        f.write(content)
    print('OK: SubscriptionController.php atualizado - redirecionamento BRL para Asaas')
else:
    print('AVISO: Linha nao encontrada. Verificar manualmente linha 109')
PYEOF

python3 /tmp/patch_sub.py
python3 << 'EOF'
content = open('app/Http/Controllers/SubscriptionController.php').read()
old = "        $subscriptionsPricingPlan = Plan::findOrFail($planId);"
new_code = "        $subscriptionsPricingPlan = Plan::with('currency')->findOrFail($planId);\n        if ($subscriptionsPricingPlan->currency && $subscriptionsPricingPlan->currency->currency_code === 'BRL') {\n            return redirect()->route('asaas.checkout.show', $planId);\n        }"
if old in content:
    open('app/Http/Controllers/SubscriptionController.php','w').write(content.replace(old,new_code))
    print('OK: SubscriptionController atualizado')
else:
    print('AVISO: nao encontrado')
EOF

php artisan config:clear && php artisan route:clear && php artisan view:clear && php artisan cache:clear && echo 'Cache limpo com sucesso'
php artisan route:list | grep asaas
cd /home/cardxfeb/public_html && curl -s -o /dev/null -w 'HTTP Status: %{http_code}\n' https://cardfyz.com/admin/asaas/checkout/7

Al-HUWAITI Shell