<?php

namespace App\Http\Livewire\Profile;

use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Laravel\Fortify\Contracts\UpdatesUserProfileInformation;


use Livewire\Component;
use Livewire\WithFileUploads;


class UpdateSettingsForm extends Component
{
    use WithFileUploads;


    /**
     * The component's state.
     *
     * @var array
     */
    public $state;


    /**
     * The new avatar for the active profile.
     *
     * @var mixed
     */
    public $photo;


    /**
     * Determine if the verification email was sent.
     *
     * @var bool
     */
    public $verificationLinkSent = false;


    /**
     * Prepare the component.
     *
     * @return void
     */
    public function mount()
    {
        $activeProfile = getActiveProfile();

        // --- Check roles and permissions --- //
        // Permissions are assigned to Users (web guard), not to Organizations/Banks/Admins
        $webUser = Auth::guard('web')->user();

        if (!$webUser) {
            abort(403, 'Unauthorized action.');
        }

        $authorized =
        ($activeProfile instanceof \App\Models\User &&
            ($webUser->can('manage users') ||
            $webUser->id === $activeProfile->id))
        ||
        ($activeProfile instanceof \App\Models\Organization &&
            ($webUser->can('manage organizations') ||
            $webUser->hasRole('Organization\\' . $activeProfile->id . '\\organization-manager') ||
            $webUser->organizations()->where('organization_user.organization_id', $activeProfile->id)->exists()))
        ||
        ($activeProfile instanceof \App\Models\Bank &&
            ($webUser->can('manage banks') ||
            $webUser->hasRole('Bank\\' . $activeProfile->id . '\\bank-manager') ||
            $webUser->banksManaged()->where('bank_user.bank_id', $activeProfile->id)->exists()))
        ||
        ($activeProfile instanceof \App\Models\Admin &&
            ($webUser->can('manage admins') ||
            $webUser->hasRole('Admin\\' . $activeProfile->id . '\\admin') ||
            $webUser->admins()->where('admin_user.admin_id', $activeProfile->id)->exists()));

        if (!$authorized) {
            abort(403, 'Unauthorized action.');
        }


        $this->state = array_merge([
            'email' => $activeProfile->email,
            'full_name' => $activeProfile->full_name,
        ], $activeProfile->withoutRelations()->toArray());
    }


    /**
     * Update the active profile's profile information.
     *
     * @param  \Laravel\Fortify\Contracts\UpdatesUserProfileInformation  $updater
     * @return void
     */
    public function updateProfileInformation()
    {
        $this->resetErrorBag();

        $activeProfile = getActiveProfile();

        // CRITICAL SECURITY: Validate user has ownership/access to this profile
        \App\Helpers\ProfileAuthorizationHelper::authorize($activeProfile);

        // Determine the profile type and table
        $profileType = get_class($activeProfile);
        $modelKey = match ($profileType) {
            'App\Models\User' => 'user',
            'App\Models\Organization' => 'organization',
            'App\Models\Bank' => 'bank',
            'App\Models\Admin' => 'admin',
            default => 'user',
        };
        $tableName = (new $profileType())->getTable();

        // Get validation rules from platform config
        $emailRules = timebank_config("rules.profile_{$modelKey}.email");
        $fullNameRules = timebank_config("rules.profile_{$modelKey}.full_name");
        $photoRules = timebank_config("rules.profile_{$modelKey}.profile_photo");

        // Convert string rules to arrays if needed
        if (is_string($emailRules)) {
            $emailRules = explode('|', $emailRules);
        }
        if (is_string($fullNameRules)) {
            $fullNameRules = explode('|', $fullNameRules);
        }
        if (is_string($photoRules)) {
            $photoRules = explode('|', $photoRules);
        }

        // Process email rules to handle unique constraint for current profile
        $processedEmailRules = [];
        foreach ($emailRules as $rule) {
            if (is_string($rule) && \Illuminate\Support\Str::startsWith(trim($rule), 'unique:')) {
                // Check if this is the unique rule for the current table
                if (preg_match("/^unique:{$tableName},email(,|$)/", trim($rule))) {
                    // Replace with a Rule object that ignores current profile
                    $processedEmailRules[] = \Illuminate\Validation\Rule::unique($tableName, 'email')->ignore($activeProfile->id);
                } else {
                    // Keep unique rules for other tables
                    $processedEmailRules[] = $rule;
                }
            } else {
                $processedEmailRules[] = $rule;
            }
        }

        // Process full_name rules to handle unique constraint for current profile
        $processedFullNameRules = [];
        if ($fullNameRules) {
            foreach ($fullNameRules as $rule) {
                if (is_string($rule) && \Illuminate\Support\Str::startsWith(trim($rule), 'unique:')) {
                    // Check if this is a unique rule for the current table (any column)
                    if (preg_match("/^unique:{$tableName},(\w+)(,|$)/", trim($rule), $matches)) {
                        $column = $matches[1];
                        // Replace with a Rule object that ignores current profile
                        $processedFullNameRules[] = \Illuminate\Validation\Rule::unique($tableName, $column)->ignore($activeProfile->id);
                    } else {
                        // Keep unique rules for other tables
                        $processedFullNameRules[] = $rule;
                    }
                } else {
                    $processedFullNameRules[] = $rule;
                }
            }
        }

        // Prepare validation rules
        $rules = [
            'state.email' => $processedEmailRules,
        ];

        // Add full_name validation for non-User profiles
        if (!($activeProfile instanceof \App\Models\User) && $processedFullNameRules) {
            $rules['state.full_name'] = $processedFullNameRules;
        }

        // Add photo validation if a photo is being uploaded
        if ($this->photo && $photoRules) {
            $rules['photo'] = $photoRules;
        }

        // Validate the input
        $this->validate($rules, [
            'state.email.required' => __('The email field is required.'),
            'state.email.email' => __('Please enter a valid email address.'),
            'state.email.unique' => __('This email address is already in use.'),
            'state.full_name.required' => __('The full name field is required.'),
            'state.full_name.max' => __('The full name must not exceed the maximum length.'),
            'photo.image' => __('The file must be an image.'),
            'photo.max' => __('The image size exceeds the maximum allowed.'),
        ]);

        // Check if the email has changed
        $emailChanged = $this->state['email'] !== $activeProfile->email;

        if ($this->photo) {
            // Delete old file if it doesn't start with "app-images/" (as those are default images)
            if ($activeProfile->profile_photo_path
                && !Str::startsWith($activeProfile->profile_photo_path, 'app-images/')) {
                Storage::disk('public')->delete($activeProfile->profile_photo_path);
            }

            // Store the new file
            $photoPath = $this->photo->store('profile-photos', 'public');
            $this->state['profile_photo_path'] = $photoPath;
        }

        // Remove protected fields from state to prevent changes
        $updateData = $this->state;
        unset($updateData['name']); // Username is always read-only

        // Full name is read-only for Users, but editable for Organizations, Banks, and Admins
        if ($activeProfile instanceof \App\Models\User) {
            unset($updateData['full_name']);
        }

        // Update records of active profile
        $activeProfile->update($updateData);

        // Refresh the component state with the updated model data
        $activeProfile = $activeProfile->fresh();
        $this->state = $activeProfile->toArray();
        $this->state['email'] = $activeProfile->email;
        $this->state['full_name'] = $activeProfile->full_name;

        // Update the session variable so the Blade view can display the new photo
        session(['activeProfilePhoto' => $this->state['profile_photo_path']]);

        // Send email verification if the email has changed
        if ($emailChanged) {
            $activeProfile->forceFill(['email_verified_at' => null])->save();
            $activeProfile->sendEmailVerificationNotification();

            // Refresh state after email verification changes
            $activeProfile = $activeProfile->fresh();
            $this->state = $activeProfile->toArray();
            $this->state['email'] = $activeProfile->email;
            $this->state['full_name'] = $activeProfile->full_name;
        }

        if (isset($this->photo)) {
            return redirect()->route('profile.settings');
        }

        $this->dispatch('saved');
    }


    /**
     * Delete active profile's profile photo.
     *
     * @return void
     */
    public function deleteProfilePhoto()
    {
        $activeProfile = getActiveProfile();

        // CRITICAL SECURITY: Validate user has ownership/access to this profile
        \App\Helpers\ProfileAuthorizationHelper::authorize($activeProfile);

        // If the existing photo path is not one of the default images, delete it
        if ($activeProfile->profile_photo_path
            && !Str::startsWith($activeProfile->profile_photo_path, 'app-images/')) {
            Storage::disk('public')->delete($activeProfile->profile_photo_path);
        }

        // Set the profile photo path to the configured default in your config file
        $defaultPath = timebank_config('profiles.' . strtolower(getActiveProfileType()) . '.profile_photo_path_default');
        $this->state['profile_photo_path'] = $defaultPath;

        // Update the active profile’s record
        $activeProfile->update(['profile_photo_path' => $defaultPath]);

        // Refresh the component state with the updated model data
        $this->state = $activeProfile->fresh()->toArray();

        // Update the session variable so the Blade view can display the new photo
        session(['activeProfilePhoto' => $defaultPath]);

        redirect()->route('profile.settings');

        // Dispatch any events if desired, for example:
        $this->dispatch('saved');
        $this->dispatch('refresh-navigation-menu');
    }


    /**
     * Send the email verification.
     *
     * @return void
     */
    public function sendEmailVerification()
    {
        $activeProfile = getActiveProfile();

        // CRITICAL SECURITY: Validate user has ownership/access to this profile
        \App\Helpers\ProfileAuthorizationHelper::authorize($activeProfile);

        $activeProfile->sendEmailVerificationNotification();

        $this->verificationLinkSent = true;
    }


    /**
     * Get the current active profile of the application.
     *
     * @return mixed
     */
    public function getUserProperty()
    {
        return getActiveProfile();
    }


    public function render()
    {
        return view('livewire.profile.update-settings-form');
    }
}
