<?php

use App\Concerns\PasswordValidationRules;
use App\Jobs\Vrm\SendMail;
use App\Mail\AdminTransactionMail;
use App\Mail\PasswordUpdatedMail;
use App\Mail\WalletTransactionMail;
use App\Models\Investment;
use App\Models\PortfolioHolding;
use App\Models\SecurityOrder;
use App\Models\Wallet;
use App\Models\WalletTransaction;
use App\Services\DefaultCurrencyService;
use App\Services\MemberNotificationService;
use App\Services\Sms\SmsNotifier;
use App\Services\Trading\TradingSettingsService;
use App\Traits\Vrm\Livewire\WithNotifications;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
use Livewire\Attributes\Computed;
use Livewire\Attributes\Layout;
use Livewire\Component;

return new #[Layout('layouts.trading')] class extends Component {
    use WithNotifications;
    use PasswordValidationRules;

    public string $withdrawAmount = '';
    public string $withdrawStep = 'amount';
    public string $withdrawResultStatus = '';
    public string $withdrawResultMessage = '';
    public float $withdrawSubmittedAmount = 0.0;
    public ?int $sellHoldingId = null;
    public string $sellShares = '';
    public string $sellStep = 'amount';
    public string $sellResultStatus = '';
    public string $sellResultMessage = '';
    public float $sellSubmittedAmount = 0.0;
    public int $sellSubmittedShares = 0;
    public string $sellSubmittedSymbol = '';
    public ?array $sellFinalToast = null;
    public string $name = '';
    public string $email = '';
    public ?string $phone = null;
    public string $current_password = '';
    public string $password = '';
    public string $password_confirmation = '';

    public function mount(): void
    {
        $this->useToasts();
        $this->name = auth()->user()->name;
        $this->email = auth()->user()->email;
        $this->phone = auth()->user()->phone;
    }

    #[Computed]
    public function wallet(): Wallet
    {
        return Wallet::query()->firstOrCreate(['user_id' => auth()->id()], ['currency_code' => app(DefaultCurrencyService::class)->code()]);
    }

    /** System default currency from ATU (single currency across the app). */
    #[Computed]
    public function currencyCode(): string
    {
        return app(DefaultCurrencyService::class)->code();
    }

    /** Current theme from user preferences (light or dark). */
    #[Computed]
    public function theme(): string
    {
        $prefs = auth()->user()->preferences ?? [];

        return $prefs['theme'] ?? 'light';
    }

    /** Trade-related only (order_debit, order_credit). */
    #[Computed]
    public function tradeTransactions()
    {
        return WalletTransaction::query()
            ->where('user_id', auth()->id())
            ->whereIn('type', ['order_debit', 'order_credit'])
            ->latest()
            ->limit(10)
            ->get();
    }

    /** Investment-related only (investment_debit, investment_credit). */
    #[Computed]
    public function investmentTransactions()
    {
        return WalletTransaction::query()
            ->where('user_id', auth()->id())
            ->whereIn('type', ['investment_debit', 'investment_credit'])
            ->latest()
            ->limit(10)
            ->get();
    }

    /** Withdrawal requests only. */
    #[Computed]
    public function withdrawalTransactions()
    {
        return WalletTransaction::query()
            ->where('user_id', auth()->id())
            ->where('type', 'withdrawal_request')
            ->latest()
            ->limit(10)
            ->get();
    }

    /** Funds currently locked in approved stock holdings (released only after selling). */
    #[Computed]
    public function stocksLockedAmount(): float
    {
        return (float) PortfolioHolding::query()
            ->where('user_id', auth()->id())
            ->sum('total_invested');
    }

    /** Funds currently locked in active investment subscriptions (released on maturity claim). */
    #[Computed]
    public function subscriptionsLockedAmount(): float
    {
        return (float) Investment::query()
            ->where('user_id', auth()->id())
            ->where('is_active', true)
            ->sum('principal_amount');
    }

    /** Funds held for pending withdrawal approvals. */
    #[Computed]
    public function pendingWithdrawalAmount(): float
    {
        return Schema::hasColumn('wallets', 'withdrawal_hold_amount') ? (float) $this->wallet->withdrawal_hold_amount : 0.0;
    }

    #[Computed]
    public function withdrawalLimits(): array
    {
        $settings = app(TradingSettingsService::class);

        return [
            'min' => $settings->withdrawalMinAmount(),
            'max' => $settings->withdrawalMaxAmount(),
        ];
    }

    #[Computed]
    public function portfolioPerformanceHoldings(): array
    {
        return PortfolioHolding::query()
            ->where('user_id', auth()->id())
            ->with('security.latestLog')
            ->get()
            ->map(function (PortfolioHolding $holding): array {
                $latestPrice = (float) $holding->security->latestPrice();
                $quantity = (int) $holding->quantity;
                $reservedQuantity = (int) ($holding->reserved_quantity ?? 0);
                $availableQuantity = max(0, $quantity - $reservedQuantity);
                $currentValue = $latestPrice * $quantity;
                $gainLossAmount = $currentValue - (float) $holding->total_invested;
                $gainLossPercent = (float) $holding->total_invested > 0 ? ($gainLossAmount / (float) $holding->total_invested) * 100 : 0.0;

                return [
                    'holding_id' => $holding->id,
                    'security_id' => $holding->security_id,
                    'symbol' => (string) $holding->security->trading_name,
                    'name' => (string) $holding->security->name,
                    'shares' => $quantity,
                    'reserved_shares' => $reservedQuantity,
                    'available_shares' => $availableQuantity,
                    'current_price' => $latestPrice,
                    'current_value' => $currentValue,
                    'gain_loss_percent' => $gainLossPercent,
                    'logo' => $holding->security->logo,
                ];
            })
            ->values()
            ->all();
    }

    #[Computed]
    public function selectedSellHolding(): ?PortfolioHolding
    {
        if ($this->sellHoldingId === null) {
            return null;
        }

        return PortfolioHolding::query()
            ->where('user_id', auth()->id())
            ->with('security.latestLog')
            ->find($this->sellHoldingId);
    }

    #[Computed]
    public function sellPreviewAmount(): float
    {
        $holding = $this->selectedSellHolding;
        if (!$holding) {
            return 0.0;
        }

        $shares = (int) $this->sellShares;
        if ($shares <= 0) {
            return 0.0;
        }

        return (float) $holding->security->latestPrice() * $shares;
    }

    #[Computed]
    public function sellLimits(): array
    {
        return app(TradingSettingsService::class)->sellLimits();
    }

    #[Computed]
    public function sellRemainingDailyShares(): int
    {
        return app(TradingSettingsService::class)->remainingDailySellSharesForUser((int) auth()->id());
    }

    #[Computed]
    public function sellMaxAllowedShares(): int
    {
        $holding = $this->selectedSellHolding;
        if (!$holding) {
            return 0;
        }

        $availableShares = max(0, (int) $holding->quantity - (int) ($holding->reserved_quantity ?? 0));
        $maxPerRequest = (int) ($this->sellLimits['max_per_request'] ?? 0);
        $maxPerDay = (int) ($this->sellLimits['max_per_day'] ?? 0);
        $remainingDaily = $maxPerDay > 0 ? $this->sellRemainingDailyShares : PHP_INT_MAX;

        $cap = min($availableShares, $maxPerRequest > 0 ? $maxPerRequest : PHP_INT_MAX, $remainingDaily);

        return max(0, $cap);
    }

    public function withdraw(): void
    {
        $this->submitWithdrawalRequest();
    }

    public function goToWithdrawConfirmation(): void
    {
        if (!$this->canSubmitWithdrawal()) {
            return;
        }

        $this->withdrawStep = 'confirm';
    }

    public function editWithdrawalAmount(): void
    {
        $this->withdrawStep = 'amount';
    }

    public function confirmWithdrawal(): void
    {
        $this->submitWithdrawalRequest();
    }

    public function resetWithdrawalFlow(): void
    {
        $this->withdrawAmount = '';
        $this->withdrawStep = 'amount';
        $this->withdrawResultStatus = '';
        $this->withdrawResultMessage = '';
        $this->withdrawSubmittedAmount = 0.0;
    }

    protected function submitWithdrawalRequest(): void
    {
        if (!$this->canSubmitWithdrawal()) {
            $this->withdrawStep = 'amount';

            return;
        }

        $amount = (float) $this->withdrawAmount;
        $created = false;
        $transactionId = null;

        DB::transaction(function () use ($amount, &$created, &$transactionId): void {
            $wallet = Wallet::query()->whereKey($this->wallet->id)->lockForUpdate()->firstOrFail();

            if ((float) $wallet->available_balance < $amount) {
                return;
            }

            if (Schema::hasColumn('wallets', 'withdrawal_hold_amount')) {
                $wallet->withdrawal_hold_amount = (float) $wallet->withdrawal_hold_amount + $amount;
            } else {
                $wallet->used_amount = (float) $wallet->used_amount + $amount;
            }
            $wallet->save();

            $transaction = WalletTransaction::query()->create([
                'wallet_id' => $wallet->id,
                'user_id' => auth()->id(),
                'type' => 'withdrawal_request',
                'status' => 'pending',
                'amount' => $amount,
                'currency_code' => app(DefaultCurrencyService::class)->code(),
                'description' => 'Wallet withdrawal request',
            ]);

            $transactionId = $transaction->id;
            $created = true;
        });

        if (!$created) {
            $this->notifyError(__('Insufficient available balance for this withdrawal.'));
            $this->withdrawStep = 'amount';

            return;
        }

        $transaction = $transactionId ? WalletTransaction::query()->find($transactionId) : null;

        if ($transaction) {
            app(MemberNotificationService::class)->notifyWithdrawalRequested($transaction);
        }

        $adminWithdrawalMessage = 'Withdrawal request submitted by ' . auth()->user()->name . ' : ' . app(DefaultCurrencyService::class)->code() . ' ' . number_format($amount, 2);
        app(SmsNotifier::class)->sendToAdmins($adminWithdrawalMessage, 'admin_transaction');
        app(SmsNotifier::class)->sendToPhone(auth()->user()->phone, 'Withdrawal request submitted successfully and is pending approval.', 'user_transaction');

        $adminEmail = config('mail.admin_address');
        if (filled($adminEmail)) {
            try {
                SendMail::dispatch((string) $adminEmail, mailable: new AdminTransactionMail(auth()->user()->name, auth()->user()->email, $amount, app(DefaultCurrencyService::class)->code(), 'withdrawal', 'submitted', 'account'), notificationType: 'admin_transaction');
            } catch (\Throwable $exception) {
                \Illuminate\Support\Facades\Log::warning('Admin withdrawal email dispatch failed.', [
                    'transaction_id' => $transaction?->id,
                    'message' => $exception->getMessage(),
                ]);
            }
        }
        try {
            SendMail::dispatch((string) auth()->user()->email, mailable: new WalletTransactionMail(auth()->user()->name, 'withdrawal_request', app(DefaultCurrencyService::class)->code(), $amount, 'pending', auth()->user()->phone, $transaction?->transaction_code, $transaction?->created_at?->format('M j, Y g:i A')), notificationType: 'user_transaction');
        } catch (\Throwable $exception) {
            \Illuminate\Support\Facades\Log::warning('Member withdrawal email dispatch failed.', [
                'transaction_id' => $transaction?->id,
                'message' => $exception->getMessage(),
            ]);
        }

        $this->withdrawSubmittedAmount = $amount;
        $this->withdrawStep = 'result';
        $this->withdrawResultStatus = 'pending';
        $this->withdrawResultMessage = __('Withdrawal request submitted. Awaiting confirmation.');
        $this->notifySuccess(__('Withdrawal request submitted. Awaiting confirmation.'));
    }

    protected function canSubmitWithdrawal(): bool
    {
        $amount = (float) $this->withdrawAmount;

        if ($amount <= 0) {
            $this->notifyError(__('Enter a valid withdrawal amount.'));

            return false;
        }

        $limits = $this->withdrawalLimits;
        if ($amount < $limits['min']) {
            $this->notifyError(__('Withdrawal amount must be at least :min.', ['min' => number_format($limits['min'], 2)]));

            return false;
        }

        if ($limits['max'] > 0 && $amount > $limits['max']) {
            $this->notifyError(__('Withdrawal amount must not exceed :max.', ['max' => number_format($limits['max'], 2)]));

            return false;
        }

        if ($this->wallet->available_balance < $amount) {
            $this->notifyError(__('Insufficient available balance for this withdrawal.'));

            return false;
        }

        return true;
    }

    public function startSellFlow(int $holdingId): void
    {
        $holding = PortfolioHolding::query()
            ->where('user_id', auth()->id())
            ->with('security')
            ->find($holdingId);

        if (!$holding) {
            $this->notifyError(__('Portfolio holding not found.'));

            return;
        }

        $availableShares = max(0, (int) $holding->quantity - (int) ($holding->reserved_quantity ?? 0));

        if ($availableShares <= 0) {
            $this->notifyError(__('No available shares to sell.'));

            return;
        }

        $remainingDaily = app(TradingSettingsService::class)->remainingDailySellSharesForUser((int) auth()->id());
        if ($remainingDaily <= 0) {
            $this->notifyError(__('You have reached your daily sell limit.'));

            return;
        }

        $this->sellHoldingId = $holdingId;
        $minimumShares = (int) app(TradingSettingsService::class)->sellMinSharesPerRequest();
        $initialShares = min(max(1, $minimumShares), $availableShares, app(TradingSettingsService::class)->sellMaxSharesPerRequest() > 0 ? app(TradingSettingsService::class)->sellMaxSharesPerRequest() : PHP_INT_MAX, $remainingDaily);
        $this->sellShares = (string) max(1, $initialShares);
        $this->sellStep = 'amount';
        $this->sellResultStatus = '';
        $this->sellResultMessage = '';
        $this->sellSubmittedAmount = 0.0;
        $this->sellSubmittedShares = 0;
        $this->sellSubmittedSymbol = '';
    }

    public function goToSellConfirmation(): void
    {
        if (!$this->canSubmitSellRequest()) {
            return;
        }

        $this->sellStep = 'confirm';
    }

    public function editSellShares(): void
    {
        $this->sellStep = 'amount';
    }

    public function confirmSell(): void
    {
        $this->submitSellRequest();
    }

    public function resetSellFlow(): void
    {
        $this->sellHoldingId = null;
        $this->sellShares = '';
        $this->sellStep = 'amount';
        $this->sellResultStatus = '';
        $this->sellResultMessage = '';
        $this->sellSubmittedAmount = 0.0;
        $this->sellSubmittedShares = 0;
        $this->sellSubmittedSymbol = '';
        $this->sellFinalToast = null;
    }

    public function clearSellFinalToast(): void
    {
        $this->sellFinalToast = null;
    }

    protected function canSubmitSellRequest(): bool
    {
        if (!app(TradingSettingsService::class)->isMarketOpen()) {
            $this->notifyError(__('Market is currently closed. Trading is unavailable.'));

            return false;
        }

        $holding = $this->selectedSellHolding;
        if (!$holding) {
            $this->notifyError(__('Portfolio holding not found.'));

            return false;
        }

        $shares = (int) $this->sellShares;
        if ($shares <= 0) {
            $this->notifyError(__('Enter a valid number of shares to sell.'));

            return false;
        }

        $minShares = (int) ($this->sellLimits['min_per_request'] ?? 1);
        if ($shares < $minShares) {
            $this->notifyError(__('Minimum shares per sell request is :min.', ['min' => $minShares]));

            return false;
        }

        $availableShares = max(0, (int) $holding->quantity - (int) ($holding->reserved_quantity ?? 0));
        if ($shares > $availableShares) {
            $this->notifyError(__('Sell shares exceed your available shares.'));

            return false;
        }

        $maxPerRequest = (int) ($this->sellLimits['max_per_request'] ?? 0);
        if ($maxPerRequest > 0 && $shares > $maxPerRequest) {
            $this->notifyError(__('Maximum shares per sell request is :max.', ['max' => $maxPerRequest]));

            return false;
        }

        $maxPerDay = (int) ($this->sellLimits['max_per_day'] ?? 0);
        if ($maxPerDay > 0 && $shares > $this->sellRemainingDailyShares) {
            $this->notifyError(__('Daily sell limit exceeded. Remaining shares for today: :remaining.', ['remaining' => $this->sellRemainingDailyShares]));

            return false;
        }

        return true;
    }

    protected function submitSellRequest(): void
    {
        if (!$this->canSubmitSellRequest()) {
            $this->sellStep = 'amount';

            return;
        }

        $shares = (int) $this->sellShares;
        $holdingId = (int) $this->sellHoldingId;
        $created = false;
        $orderId = null;
        $totalAmount = 0.0;
        $symbol = '';

        DB::transaction(function () use ($holdingId, $shares, &$created, &$orderId, &$totalAmount, &$symbol): void {
            $holding = PortfolioHolding::query()
                ->where('user_id', auth()->id())
                ->whereKey($holdingId)
                ->with('security.latestLog')
                ->lockForUpdate()
                ->firstOrFail();

            $availableShares = max(0, (int) $holding->quantity - (int) ($holding->reserved_quantity ?? 0));
            if ($shares > $availableShares) {
                return;
            }

            $pricePerShare = max(0.0001, (float) $holding->security->latestPrice());
            $totalAmount = $pricePerShare * $shares;
            $symbol = (string) $holding->security->trading_name;

            $holding->reserved_quantity = (int) ($holding->reserved_quantity ?? 0) + $shares;
            $holding->save();

            $order = SecurityOrder::query()->create([
                'user_id' => auth()->id(),
                'security_id' => $holding->security_id,
                'wallet_id' => $this->wallet->id,
                'order_type' => 'sell',
                'status' => 'pending',
                'price_per_share' => $pricePerShare,
                'quantity' => $shares,
                'volume' => $shares,
                'total_amount' => $totalAmount,
                'currency_code' => app(DefaultCurrencyService::class)->code(),
                'traded_at' => now(),
                'profit_loss_amount' => 0,
                'profit_loss_percent' => 0,
                'is_active' => false,
            ]);

            WalletTransaction::query()->create([
                'wallet_id' => $this->wallet->id,
                'user_id' => auth()->id(),
                'type' => 'order_credit',
                'status' => 'pending',
                'amount' => $totalAmount,
                'currency_code' => app(DefaultCurrencyService::class)->code(),
                'description' => "Pending sell order for {$symbol}",
                'meta' => [
                    'security_id' => $holding->security_id,
                    'quantity' => $shares,
                    'order_type' => 'sell',
                    'origin' => 'account_portfolio_performance',
                ],
            ]);

            $orderId = $order->id;
            $created = true;
        });

        if (!$created) {
            $this->notifyError(__('Unable to submit sell request. Check available shares and try again.'));
            $this->sellStep = 'amount';

            return;
        }

        $adminEmail = config('mail.admin_address');
        if (filled($adminEmail)) {
            SendMail::dispatch((string) $adminEmail, mailable: new AdminTransactionMail(auth()->user()->name, auth()->user()->email, $totalAmount, app(DefaultCurrencyService::class)->code(), 'shares_sell', 'submitted', 'account'), notificationType: 'admin_transaction');
        }
        app(SmsNotifier::class)->sendToPhone(auth()->user()->phone, "Sell order submitted for {$symbol}.", 'user_transaction');

        $this->sellSubmittedAmount = $totalAmount;
        $this->sellSubmittedShares = $shares;
        $this->sellSubmittedSymbol = $symbol;
        $this->sellStep = 'result';
        $this->sellResultStatus = 'pending';
        $this->sellResultMessage = __('Sell request submitted. Awaiting admin approval.');
        $this->sellFinalToast = [
            'title' => __('Sell Request Submitted'),
            'description' => __('Your sell request for :shares shares of :symbol has been received.', [
                'shares' => number_format($shares),
                'symbol' => $symbol,
            ]),
        ];
        $this->notifySuccess(__('Sell request submitted. Awaiting admin approval.'));
    }

    public function setTheme(string $theme): void
    {
        if (!in_array($theme, ['light', 'dark'], true)) {
            return;
        }

        $user = auth()->user();
        $prefs = $user->preferences ?? [];
        $prefs['theme'] = $theme;
        $user->preferences = $prefs;

        $this->dispatch('theme-changed', theme: $theme);
    }

    public function updateProfileInformation(): void
    {
        $this->notifyError(__('Profile information is view only.'));
    }

    public function updatePassword(): void
    {
        $validated = $this->validate([
            'current_password' => ['required', 'string'],
            'password' => $this->passwordRules(),
        ]);

        $user = auth()->user();

        if (!Hash::check($validated['current_password'], $user->password)) {
            $this->addError('current_password', __('The current password is incorrect.'));

            return;
        }

        $user->update([
            'password' => $validated['password'],
        ]);

        app(SmsNotifier::class)->sendToPhone($user->phone, 'Your account password was updated successfully.', 'user_password_updated');
        try {
            SendMail::dispatch($user->email, mailable: new PasswordUpdatedMail(), notificationType: 'user_password_updated');
        } catch (\Throwable $exception) {
            \Illuminate\Support\Facades\Log::warning('Password updated email dispatch failed.', [
                'user_id' => $user->id,
                'message' => $exception->getMessage(),
            ]);
        }

        $this->reset('current_password', 'password', 'password_confirmation');
        $this->notifySuccess(__('Password updated successfully.'));
    }

    protected function view($data = [])
    {
        return app('view')->file('/home/ziidfelj/home.ziidi.trade/storage/framework/views/livewire/views/af99910e.blade.php', $data);
    }
}; 