<?php

namespace App\Services;

use App\Models\BotSetting;
use App\Models\BotSignal;
use App\Models\Instrument;
use App\Models\Notification;
use App\Models\Order;
use App\Models\Position;
use App\Models\TradeJournal;
use App\Models\User;
use App\Services\FlatTrade\BrokerAccountResolver;
use App\Services\FlatTrade\FlatTradeAccountSyncService;
use App\Services\MarketData\MarketDataSyncService;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;

class DashboardService
{
    public function __construct(
        private BrokerAccountResolver $resolver,
        private MarketDataSyncService $marketData,
        private FlatTradeAccountSyncService $accountSync,
    ) {}

    public function overview(User $user): array
    {
        $this->refreshLiveData($user);

        $openPositions = Position::query()
            ->where('user_id', $user->id)
            ->where('is_open', true)
            ->with('instrument.latestTick')
            ->get();

        $broker = $user->brokerAccount?->fresh();
        $unrealized = $broker?->is_connected
            ? (float) $broker->unrealized_pnl_total
            : $openPositions->sum('unrealized_pnl');
        $realized = $broker?->is_connected
            ? (float) $broker->realized_pnl_total
            : Position::query()
                ->where('user_id', $user->id)
                ->where('is_open', false)
                ->whereDate('closed_at', today())
                ->sum('realized_pnl');

        $botSettings = BotSetting::firstOrCreate(
            ['user_id' => $user->id],
            ['bot_enabled' => false, 'auto_trade' => false, 'bot_status' => 'idle']
        );

        $availableBalance = $broker?->is_connected ? (float) $broker->available_balance : 0.0;
        $feedAccount = $this->resolver->marketFeedAccount();

        $nifty = $this->marketData->getIndexQuoteForDashboard('NIFTY50');
        $vix = $this->marketData->getIndexQuoteForDashboard('INDIA_VIX');

        return [
            'total_equity' => $availableBalance + $unrealized,
            'available_balance' => $availableBalance,
            'margin_used' => $broker?->is_connected ? (float) $broker->margin_used : 0,
            'unrealized_pnl' => $unrealized,
            'realized_pnl' => $realized,
            'open_positions_count' => $openPositions->count(),
            'bot_settings' => $botSettings,
            'broker_connected' => (bool) ($broker?->is_connected),
            'broker_has_credentials' => $broker && app(\App\Services\FlatTrade\FlatTradeAuthService::class)->hasCredentials($broker),
            'broker_label' => 'FlatTrade',
            'market_feed_connected' => (bool) $feedAccount,
            'last_synced_at' => $broker?->last_synced_at,
            'nifty' => $nifty,
            'vix' => $vix,
            'scan_instruments' => $this->scanWatchInstruments(),
            'recent_orders' => Order::query()
                ->where('user_id', $user->id)
                ->latest()
                ->limit(20)
                ->get(),
            'open_positions' => $openPositions,
            'notifications' => Notification::where('user_id', $user->id)->latest()->limit(10)->get(),
            'unread_notifications' => Notification::where('user_id', $user->id)->whereNull('read_at')->count(),
            'agent_signals' => BotSignal::where('user_id', $user->id)->latest()->limit(20)->get(),
            'trade_journal' => TradeJournal::where('user_id', $user->id)->latest()->limit(20)->get(),
        ];
    }

    public function scanWatchInstruments(): Collection
    {
        return Instrument::query()
            ->where('underlying', 'NIFTY')
            ->where('instrument_kind', 'option')
            ->where('is_active', true)
            ->with(['latestTick', 'latestGreek'])
            ->orderBy('strike_price')
            ->orderBy('option_type')
            ->get();
    }

    private function refreshLiveData(User $user): void
    {
        if ($user->brokerAccount?->is_connected) {
            try {
                $this->accountSync->syncUser($user);
            } catch (\Throwable $e) {
                Log::warning('User account sync failed', ['user_id' => $user->id, 'error' => $e->getMessage()]);
            }
        }

        if (! $this->resolver->marketFeedAccount()) {
            return;
        }

        $lastMarketSync = Instrument::query()
            ->where('instrument_kind', 'option')
            ->whereHas('marketTicks', fn ($q) => $q->where('tick_at', '>=', now()->subMinutes(2)))
            ->exists();

        if ($lastMarketSync) {
            return;
        }

        try {
            $this->marketData->syncScanUniverse();
        } catch (\Throwable $e) {
            Log::warning('Market data sync failed', ['error' => $e->getMessage()]);
        }
    }
}
