<?php

namespace App\Http\Livewire\Profile;

use App\Mail\UserDeletedMail;
use Illuminate\Contracts\Auth\StatefulGuard;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Validation\ValidationException;
use Laravel\Jetstream\Contracts\DeletesUsers;
use Livewire\Component;
use WireUi\Traits\WireUiActions;


class DeleteUserForm extends Component
{
    use WireUiActions;



    /**
     * Indicates if user deletion is being confirmed.
     *
     * @var bool
     */
    public $confirmingUserDeletion = false;

    /**
     * The user's current password.
     *
     * @var string
     */
    public $password = '';

    /**
     * Balance handling option selected by user.
     *
     * @var string
     */
    public $balanceHandlingOption = 'delete';

    /**
     * Selected organization account ID for balance donation.
     *
     * @var int|null
     */
    public $donationAccountId = null;

    /**
     * User's accounts with balances.
     *
     * @var \Illuminate\Support\Collection
     */
    public $accounts;

    /**
     * Total balance across all accounts.
     *
     * @var float|int
     */
    public $totalBalance = 0;

    /**
     * Whether any account has a negative balance.
     *
     * @var bool
     */
    public $hasNegativeBalance = false;

    /**
     * Whether the profile is a central bank (level = 0).
     *
     * @var bool
     */
    public $isCentralBank = false;

    /**
     * Whether the profile is the final admin.
     *
     * @var bool
     */
    public $isFinalAdmin = false;

    /**
     * Whether the donation would exceed the receiving account's limit.
     *
     * @var bool
     */
    public $donationExceedsLimit = false;

    /**
     * Error message for donation limit exceeded.
     *
     * @var string|null
     */
    public $donationLimitError = null;

    /**
     * Listener to receive toAccountId from ToAccount component.
     */
    protected $listeners = ['toAccountId' => 'setDonationAccountId'];

    /**
     * Called when balanceHandlingOption is updated.
     *
     * @return void
     */
    public function updatedBalanceHandlingOption()
    {
        $this->checkDonationLimits();
    }

    /**
     * Set the donation account ID from ToAccount component.
     *
     * @param int|null $accountId
     * @return void
     */
    public function setDonationAccountId($accountId)
    {
        $this->donationAccountId = $accountId;
        $this->checkDonationLimits();
    }

    /**
     * Check if the donation would exceed the receiving account's limits.
     *
     * @return void
     */
    protected function checkDonationLimits()
    {
        // Reset error state
        $this->donationExceedsLimit = false;
        $this->donationLimitError = null;

        // If no donation account selected or no balance to donate, skip check
        if (!$this->donationAccountId || $this->totalBalance <= 0) {
            return;
        }

        // Get the donation account
        $donationAccount = \App\Models\Account::find($this->donationAccountId);
        if (!$donationAccount) {
            return;
        }

        // Clear cache for fresh balance
        \Cache::forget("account_balance_{$donationAccount->id}");

        // Get current balance of the receiving account
        $currentBalance = $donationAccount->balance;

        // Calculate the maximum receivable amount
        // limitMaxTo = limit_max - limit_min (similar to Pay.php logic)
        $limitMaxTo = $donationAccount->limit_max - $donationAccount->limit_min;

        // Calculate available budget for receiving
        $transferBudgetTo = $limitMaxTo - $currentBalance;

        // Check if donation amount exceeds the receiving account's budget
        if ($this->totalBalance > $transferBudgetTo) {
            $this->donationExceedsLimit = true;

            // Check if the receiving account holder's balance is public
            $holderType = $donationAccount->accountable_type;
            $balancePublic = timebank_config('account_info.' . strtolower(class_basename($holderType)) . '.balance_public', false);

            if ($balancePublic) {
                $this->donationLimitError = __('The selected account cannot receive this donation amount due to account limits. Please select a different account or delete your balance instead.', [
                    'amount' => tbFormat($transferBudgetTo)
                ]);
            } else {
                $this->donationLimitError = __('The selected organization account cannot receive this donation amount due to account limits. Please select a different organization or delete your balance instead.');
            }
        }
    }

    /**
     * Confirm that the user would like to delete their account.
     *
     * @return void
     */
    public function confirmUserDeletion()
    {
        $this->resetErrorBag();
        $this->password = '';
        $this->dispatch('confirming-delete-user');
        $this->confirmingUserDeletion = true;
    }

    /**
     * Delete the current user.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Laravel\Jetstream\Contracts\DeletesUsers  $deleter
     * @param  \Illuminate\Contracts\Auth\StatefulGuard  $auth
     * @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse
     */
        public function deleteUser(Request $request, DeletesUsers $deleter, StatefulGuard $auth)
    {
        $this->resetErrorBag();

        // Get the active profile using helper
        $profile = getActiveProfile();

        if (!$profile) {
            throw new \Exception('No active profile found.');
        }

        // CRITICAL SECURITY: Validate user has ownership/access to this profile
        // This prevents IDOR (Insecure Direct Object Reference) attacks where
        // a user manipulates session data to delete profiles they don't own
        \App\Helpers\ProfileAuthorizationHelper::authorize($profile);

        // Check if trying to delete a central bank
        if ($profile instanceof \App\Models\Bank && isset($profile->level) && $profile->level == 0) {
            throw ValidationException::withMessages([
                'password' => [__('Central bank (level 0) cannot be deleted. Central banks are essential for currency creation and management.')],
            ]);
        }

        // Check if trying to delete the final admin
        if ($profile instanceof \App\Models\Admin) {
            $activeAdminCount = \App\Models\Admin::whereNull('deleted_at')->count();
            if ($activeAdminCount <= 1) {
                throw ValidationException::withMessages([
                    'password' => [__('Final administrator cannot be deleted. At least one administrator account must remain active in the system.')],
                ]);
            }
        }

        // Determine which password to check based on profile type
        if ($profile instanceof \App\Models\User || $profile instanceof \App\Models\Organization) {
            // User or Organization: validate against base user password
            // Organizations don't have their own password (passwordless)
            $authenticatedUser = Auth::user();
            if (! Hash::check($this->password, $authenticatedUser->password)) {
                throw ValidationException::withMessages([
                    'password' => [__('This password does not match our records.')],
                ]);
            }
        } elseif ($profile instanceof \App\Models\Bank || $profile instanceof \App\Models\Admin) {
            // Bank or Admin: validate against their own password
            if (! Hash::check($this->password, $profile->password)) {
                throw ValidationException::withMessages([
                    'password' => [__('This password does not match our records.')],
                ]);
            }
        } else {
            throw new \Exception('Unknown profile type.');
        }

        // Validate balance handling option if donation is selected
        if ($this->balanceHandlingOption === 'donate' && !$this->donationAccountId) {
            throw ValidationException::withMessages([
                'donationAccountId' => [__('Please select an organization account to donate your balance to.')],
            ]);
        }

        // Check if donation would exceed limits
        if ($this->balanceHandlingOption === 'donate' && $this->donationExceedsLimit) {
            throw ValidationException::withMessages([
                'donationAccountId' => [$this->donationLimitError ?? __('The selected organization account cannot receive this donation amount.')],
            ]);
        }

        // Determine table name based on profile type
        $profileTable = $profile->getTable();

        // Get the profile's updated_at timestamp
        $time = DB::table($profileTable)
                ->where('id', $profile->id)
                ->pluck('updated_at')
                ->first();

        $time = Carbon::parse($time); // Convert the time to a Carbon instance

        // Pass balance handling options to the deleter
        $result = $deleter->delete(
            $profile->fresh(),
            $this->balanceHandlingOption,
            $this->donationAccountId
        );

        $this->confirmingUserDeletion = false;

        if ($result['status'] === 'success') {

            $result['time'] = $time->translatedFormat('j F Y, H:i');
            $result['deletedUser'] = $profile;
            $result['mail'] = $profile->email;
            $result['balanceHandlingOption'] = $this->balanceHandlingOption;
            $result['totalBalance'] = $this->totalBalance;
            $result['donationAccountId'] = $this->donationAccountId;
            $result['gracePeriodDays'] = timebank_config('delete_profile.grace_period_days', 30);

            // Get donation account details if donated
            if ($this->balanceHandlingOption === 'donate' && $this->donationAccountId) {
                $donationAccount = \App\Models\Account::find($this->donationAccountId);
                if ($donationAccount && $donationAccount->accountable) {
                    $result['donationAccountName'] = $donationAccount->name;
                    $result['donationOrganizationName'] = $donationAccount->accountable->name;
                }
            }

            Log::notice('Profile deleted: ' . $result['deletedUser']);
            Mail::to($profile->email)->queue(new UserDeletedMail($result));

            // Handle logout based on profile type
            if ($profile instanceof \App\Models\User) {
                // User deletion: logout completely from all guards
                $auth->logout();
                session()->invalidate();
                session()->regenerateToken();
                // Re-flash the result data after session invalidation
                session()->flash('result', $result);
            } else {
                // Flash result for non-user profiles
                session()->flash('result', $result);
                // Non-user profile deletion (Organization/Bank/Admin):
                // Only logout from the specific guard and switch back to base user
                $profileType = strtolower(class_basename($profile));

                if ($profileType === 'organization') {
                    Auth::guard('organization')->logout();
                } elseif ($profileType === 'bank') {
                    Auth::guard('bank')->logout();
                } elseif ($profileType === 'admin') {
                    Auth::guard('admin')->logout();
                }

                // Switch back to base user profile
                $baseUser = Auth::guard('web')->user();
                if ($baseUser) {
                    session(['activeProfileType' => 'App\\Models\\User']);
                    session(['activeProfileId' => $baseUser->id]);
                    session(['activeProfileName' => $baseUser->name]);
                    session(['activeProfilePhoto' => $baseUser->profile_photo_path]);
                    session(['active_guard' => 'web']);
                }
            }

            return redirect()->route('goodbye-deleted-user');
            
        } else {
            // Trigger WireUi error notification
            $this->notification()->error(
                $title = __('Deletion Failed'),
                $description = __('There was an error deleting your profile: ') . $result['message']
            );

            Log::warning('Profile deletion failed for profile ID: ' . $profile->id . ' (Type: ' . get_class($profile) . ')');
            Log::error('Error message: ' . $result['message']);

            return redirect()->back();
        }
    }


    /**
     * Load user accounts and calculate balances.
     *
     * @return void
     */
    public function mount()
    {
        $this->loadAccounts();
    }

    /**
     * Load and calculate account balances.
     *
     * @return void
     */
    public function loadAccounts()
    {
        // Get the active profile using helper (could be User, Organization, Bank, etc.)
        $profile = getActiveProfile();

        // Check if profile is a central bank (level = 0)
        if ($profile instanceof \App\Models\Bank && isset($profile->level) && $profile->level == 0) {
            $this->isCentralBank = true;
        }

        // Check if profile is the final admin
        if ($profile instanceof \App\Models\Admin) {
            $activeAdminCount = \App\Models\Admin::whereNull('deleted_at')->count();
            if ($activeAdminCount <= 1) {
                $this->isFinalAdmin = true;
            }
        }

        // Check if profile exists and has accounts method
        if (!$profile || !method_exists($profile, 'accounts')) {
            $this->accounts = collect();
            $this->totalBalance = 0;
            $this->hasNegativeBalance = false;
            return;
        }

        // Get all active, non-removed accounts
        $userAccounts = $profile->accounts()
            ->active()
            ->notRemoved()
            ->get();

        // Clear cache and calculate balances
        $this->accounts = collect();
        $this->totalBalance = 0;
        $this->hasNegativeBalance = false;

        foreach ($userAccounts as $account) {
            // Clear cache for fresh balance
            Cache::forget("account_balance_{$account->id}");

            $balance = $account->balance;

            $this->accounts->push([
                'id' => $account->id,
                'name' => __('messages.' . $account->name . '_account'),
                'balance' => $balance,
                'balanceFormatted' => tbFormat($balance),
            ]);

            $this->totalBalance += $balance;

            if ($balance < 0) {
                $this->hasNegativeBalance = true;
            }
        }
    }

    /**
     * Render the component.
     *
     * @return \Illuminate\View\View
     */
    public function render()
    {
        $showBalanceOptions = timebank_config('delete_profile.account_balances.donate_balances_to_organization_account_specified', false);

        return view('profile.delete-user-form', [
            'showBalanceOptions' => $showBalanceOptions,
        ]);
    }
}
