<?php

namespace App\Http\Livewire\ProfileBank;

use App\Models\Bank;
use App\Traits\FormHelpersTrait;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Laravel\Jetstream\Features;
use Laravel\Jetstream\HasProfilePhoto;
use Livewire\Component;
use Livewire\WithFileUploads;

class UpdateProfileBankForm extends Component
{
    use WithFileUploads;
    use HasProfilePhoto;
    use FormHelpersTrait;

    public $state = [];
    public $bank;
    public $photo;
    public $languages;
    public $website;

    //Important
    // Authorization is handled in mount() method instead of middleware to support multi-guard system
    // protected $middleware = [
    //     'can:manage banks',
    // ];

    protected $listeners = ['languagesToParent'];


    public function rules()
    {
        return [
            'photo' => timebank_config('rules.profile_bank.profile_photo'),
            'state.about' => timebank_config('rules.profile_bank.about', 400),
            'state.about_short' => timebank_config('rules.profile_bank.about_short', 150),
            'state.motivation' => timebank_config('rules.profile_bank.motivation', 300),
            'languages' => timebank_config('rules.profile_bank.languages', 'required'),
            'languages.id' => timebank_config('rules.profile_bank.languages_id', 'int'),
            'state.date_of_birth' => timebank_config('rules.profile_bank.date_of_birth', 'nullable|date'),
            'website' => timebank_config('rules.profile_bank.website', 'nullable|regex:/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/i'),
        ];
    }

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

        // Check if active profile is a Bank
        if (!($activeProfile instanceof \App\Models\Bank)) {
            abort(403, 'Unauthorized action.');
        }

        // Check if web user (who owns the bank) has permission or bank manager role
        // Permissions are assigned to Users (web guard), not to Banks
        $webUser = Auth::guard('web')->user();

        // User is authorized if ANY of these conditions are true:
        // 1. Has global "manage banks" permission (admin)
        // 2. Has bank manager role for this specific bank
        // 3. Is linked to this bank (owner/member)
        $authorized = ($webUser && (
            $webUser->can('manage banks') ||
            $webUser->hasRole('Bank\\' . $activeProfile->id . '\\bank-manager') ||
            $webUser->banksManaged()->where('bank_user.bank_id', $activeProfile->id)->exists()
        ));

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


        $this->state = Bank::find(session('activeProfileId'))->toArray();
        $this->website = $this->state['website'];
        $this->bank = Bank::find(session('activeProfileId'));

        $this->getLanguages();
    }


    /**
     * Get the profile photo URL for the bank
     *
     * @return string
     */
    public function getProfilePhotoUrlProperty()
    {
        if (!$this->bank) {
            return '';
        }

        // Use asset() for app-images, Storage::url() for uploaded photos
        if (str_starts_with($this->bank->profile_photo_path, 'app-images/')) {
            return asset('storage/' . $this->bank->profile_photo_path);
        }

        return url(Storage::url($this->bank->profile_photo_path));
    }


    public function getLanguages()
    {
        // Create a language options collection that combines all language and competence options
        $langOptions = DB::table('languages')->get(['id','name']);
        $compOptions = DB::table('language_competences')->get(['id','name']);
        $langOptions = collect(Arr::crossJoin($langOptions, $compOptions));
        $langOptions = $langOptions->Map(function ($language, $key) {
            return [
                'id' => $key,   // index key is needed to select values in dropdown (option-value)
                'langId' => $language[0]->id,
                'compId' => $language[1]->id,
                'name' => trans($language[0]->name) . ' - ' . trans($language[1]->name),
            ];
        });

        // Create an array of the pre-selected language options
        $languages = $this->bank->languages;
        $languages = $languages->map(function ($language, $key) use ($langOptions) {
            $competence = DB::table('language_competences')->find($language->pivot->competence);
            $langSelected = collect($langOptions)->where('name', trans($language->name) . ' - ' . trans($competence->name));
            return [
                $langSelected->keys()
            ];
        });
        $languages = $languages->flatten();

        // Create a selected language collection that holds the selected languages with their selected competences
        $this->languages = collect($langOptions)->whereIn('id', $languages)->values();
    }


    public function languagesToParent($values)
    {
        $this->languages = $values;
        $this->validateOnly('languages');
    }


    /**
     * Validate a single field when updated.
     * This is the 1st validation method on this form.
     *
     * @param  mixed $field
     * @return void
     */
    public function updated($field)
    {
        if ($field == 'website') {
            // If website is not empty, add URL scheme
            if (!empty($this->website)) {
                $this->website = $this->addUrlScheme($this->website);
            } else {
                // If website is empty, remove 'https://' prefix
                $this->website = str_replace('https://', '', $this->website);
            }
        }

        $this->validateOnly($field);
    }


    /**
    * Update the bank's profile contact information.
    *
    * @return void
    */
    public function updateProfilePersonalForm()
    {
        $bank = getActiveProfile();

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

        if (isset($this->photo)) {
            $bank->updateProfilePhoto($this->photo);  // Trait (use HasProfilePhoto) needs to attached to Bank model for this to work
        }

        $this->validate();  // 2nd validation, just before save method

        $bank->about = $this->state['about'];
        $bank->about_short = $this->state['about_short'];
        $bank->motivation = $this->state['motivation'];
        $bank->website =  str_replace(['http://', 'https://', ], '', $this->website);

        if (isset($this->languages)) {

            $languages = collect($this->languages)->Map(function ($lang, $key) use ($bank) {
                return [
                    'language_id' => $lang['langId'],
                    'competence' => $lang['compId'],
                    'languagable_type' => Bank::class,
                    'languagable_id' => $bank->id,
                ];
            })->toArray();

            $bank->languages()->detach(); // Remove all languages of this bank before inserting the new ones
            DB::table('languagables')->insert($languages);
        }

        $bank->save();
        $this->dispatch('saved');
        session(['activeProfilePhoto' => $bank->profile_photo_path ]);
        redirect()->route('profile.edit');
    }

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

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

        if (! Features::managesProfilePhotos()) {
            return;
        }

        if (is_null($bank->profile_photo_path)) {
            return;
        }

        $defaultPath = timebank_config('profiles.bank.profile_photo_path_default');

        // Delete uploaded photos (profile-photos/) and reset to default
        if (str_starts_with($bank->profile_photo_path, 'profile-photos/')) {
            Storage::disk(isset($_ENV['VAPOR_ARTIFACT_NAME']) ? 's3' : config('jetstream.profile_photo_disk', 'public'))->delete($bank->profile_photo_path);

            $bank->forceFill([
                'profile_photo_path' => $defaultPath,
            ])->save();

            Session(['activeProfilePhoto'=> $bank->profile_photo_path ]);
        }
        // If current path is app-images but not the correct default, update it
        elseif (str_starts_with($bank->profile_photo_path, 'app-images/') && $bank->profile_photo_path !== $defaultPath) {
            $bank->forceFill([
                'profile_photo_path' => $defaultPath,
            ])->save();

            Session(['activeProfilePhoto'=> $bank->profile_photo_path ]);
        }

        $this->dispatch('saved');
        redirect()->route('profile.edit');
    }


    public function addUrlScheme($url, $scheme = 'https://')
    {
        return parse_url($url, PHP_URL_SCHEME) === null ?
        $scheme . $url : $url;
    }


    /**
     * Gets the label for the "about_short" input field, including a character counter if applicable.
     * The character counter needs to use the `characterLeftCounter` method from the `FormHelpersTrait`.
     *
     * @return string The label for the "about" field, optionally including the remaining character count.
     */
    public function getAboutLabelProperty()
    {
        $maxInput = timebank_config('rules.profile_bank.about_max_input');
        $baseLabel =  __('Introduce your bank in a few sentences');
        $counter = $this->characterLeftCounter($this->state['about'] ?? '', $maxInput);

        return $counter ? $baseLabel . ' (' . $counter . ')' : $baseLabel;
    }


    /**
     * Gets the label for the "about_short" input field, including a character counter if applicable.
     * The character counter needs to use the `characterLeftCounter` method from the `FormHelpersTrait`.
     *
     * @return string The label for the "about_short" field, optionally including the remaining character count.
     */
    public function getAboutShortLabelProperty()
    {
        $maxInput = timebank_config('rules.profile_bank.about_short_max_input');
        $baseLabel = __('Introduction in one sentence');
        $counter = $this->characterLeftCounter($this->state['about_short'] ?? '', $maxInput);

        return $counter ? $baseLabel . ' (' . $counter . ')' : $baseLabel;
    }

    /**
     * Gets the label for the "motivation" input field, including a character counter if applicable.
     * The character counter needs to use the `characterLeftCounter` method from the `FormHelpersTrait`.
     *
     * @return string The label for the "about_short" field, optionally including the remaining character count.
     */
    public function getMotivationLabelProperty()
    {
        $maxInput = timebank_config('rules.profile_bank.motivation_max_input');
        $baseLabel = __('What is your motivation to start a ' . platform_name_short() . '?');
        $counter = $this->characterLeftCounter($this->state['motivation'] ?? '', $maxInput);

        return $counter ? $baseLabel . ' (' . $counter . ')' : $baseLabel;
    }

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