<?php

namespace App\Services\FlatTrade;

use App\Models\BrokerAccount;
use App\Models\Notification;
use App\Models\User;
use Illuminate\Support\Facades\Crypt;

class FlatTradeAuthService
{
    public function __construct(private FlatTradeClient $client) {}

    public function saveCredentials(User $user, string $apiKey, string $apiSecret): BrokerAccount
    {
        $account = BrokerAccount::firstOrCreate(
            ['user_id' => $user->id],
            ['broker' => 'flattrade']
        );

        $account->update([
            'api_key' => $apiKey,
            'api_secret' => Crypt::encryptString($apiSecret),
        ]);

        app(BrokerAccountResolver::class)->markAsMarketFeedProvider($account->fresh(), $user);

        return $account->fresh();
    }

    public function getAuthorizationUrl(BrokerAccount $account): string
    {
        if (! filled($account->api_key)) {
            throw new \RuntimeException('Save your FlatTrade API Key first.');
        }

        return config('flattrade.auth_url').'?app_key='.urlencode($account->api_key);
    }

    public function handleCallback(User $user, string $requestCode): BrokerAccount
    {
        $account = $user->brokerAccount;
        if (! $account || ! filled($account->api_key) || ! filled($account->api_secret)) {
            throw new \RuntimeException('Add and save your FlatTrade API credentials before connecting.');
        }

        $apiSecret = Crypt::decryptString($account->api_secret);
        $response = $this->client->exchangeAuthCode($account->api_key, $requestCode, $apiSecret);

        if (($response['stat'] ?? '') !== 'Ok' || empty($response['token'])) {
            throw new \RuntimeException($response['emsg'] ?? 'Failed to obtain FlatTrade session token.');
        }

        $clientId = (string) ($response['client'] ?? $user->id);
        $actId = (string) ($response['actid'] ?? $clientId);

        $account->update([
            'client_id' => $clientId,
            'act_id' => $actId,
            'access_token' => $response['token'],
            'token_expires_at' => now()->endOfDay(),
            'is_connected' => true,
            'last_synced_at' => now(),
        ]);

        app(BrokerAccountResolver::class)->markAsMarketFeedProvider($account->fresh(), $user);

        app(FlatTradeAccountSyncService::class)->syncUser($user);

        Notification::create([
            'user_id' => $user->id,
            'type' => 'broker_connected',
            'title' => 'FlatTrade Connected',
            'message' => 'Your FlatTrade account is connected. Balance and positions synced.',
        ]);

        return $account->fresh();
    }

    public function bindClient(FlatTradeClient $client, BrokerAccount $account): FlatTradeClient
    {
        if (! $account->access_token || ! $account->client_id) {
            throw new \RuntimeException('Broker account is not connected.');
        }

        return $client->setSession(
            $account->client_id,
            $account->act_id ?: $account->client_id,
            $account->access_token
        );
    }

    public function isTokenValid(BrokerAccount $account): bool
    {
        return $account->is_connected
            && $account->access_token
            && ($account->token_expires_at === null || $account->token_expires_at->isFuture());
    }

    public function hasCredentials(BrokerAccount $account): bool
    {
        return filled($account->api_key) && filled($account->api_secret);
    }
}
