<?php

namespace App\Http\Controllers\Web;

use App\Http\Controllers\Controller;
use App\Models\Company;
use App\Models\CompanySetting;
use App\Models\User;
use App\Models\UserProfileIntro;
use App\Models\UserSession;
use App\Services\TenantMailConfig;
use App\Services\TwoFactorService;
use App\Services\UserSessionService;
use App\Support\EmployeeValidation;
use App\Support\FormTextRules;
use Carbon\CarbonInterface;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Storage;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Password;

class SettingsController extends Controller
{
    private function companyId(): ?int
    {
        return auth()->user()?->company_id;
    }

    private function getCompanySetting(string $key, $default = null)
    {
        if (! $this->companyId()) {
            return $default;
        }
        $s = CompanySetting::withoutGlobalScopes()->where('company_id', $this->companyId())->where('key', $key)->first();

        return $s ? $s->value : $default;
    }

    private function setCompanySetting(string $key, ?string $value): void
    {
        if (! $this->companyId()) {
            return;
        }
        CompanySetting::withoutGlobalScopes()->updateOrCreate(
            ['company_id' => $this->companyId(), 'key' => $key],
            ['value' => $value ?? '']
        );
    }

    public function index()
    {
        $settings = CompanySetting::orderBy('key')->get();
        $company = auth()->user()?->company;
        $sequence = null;
        if ($this->companyId()) {
            $sequence = DB::table('employee_number_sequences')
                ->where('company_id', $this->companyId())
                ->first();
        }
        $employeeNumberPrefix = strtoupper(trim((string) ($sequence->prefix ?? null)));
        $employeeNumberDigits = max(1, min(10, (int) ($sequence->digits ?? 1)));
        $twoFactorPolicy = $this->getCompanySetting(TwoFactorService::SETTING_POLICY, TwoFactorService::POLICY_OPTIONAL);
        $twoFactorDefaultMethod = $this->getCompanySetting(TwoFactorService::SETTING_DEFAULT_METHOD, TwoFactorService::METHOD_EMAIL);
        $tab = (string) request('tab', 'general');
        if (! in_array($tab, ['general', 'branding', 'security'], true)) {
            $tab = 'general';
        }

        return view('settings.index', compact(
            'settings',
            'company',
            'employeeNumberPrefix',
            'employeeNumberDigits',
            'twoFactorPolicy',
            'twoFactorDefaultMethod',
            'tab',
        ));
    }

    public function securityUpdate(Request $request, TwoFactorService $twoFactor)
    {
        if (! $this->companyId()) {
            return redirect()->route('settings.index')->with('error', 'Company not found.');
        }

        $validated = $request->validate([
            'two_factor_policy' => 'required|in:off,optional,required',
            'two_factor_default_method' => 'required|in:email,totp',
        ]);

        $previousPolicy = $this->getCompanySetting(TwoFactorService::SETTING_POLICY, TwoFactorService::POLICY_OPTIONAL);

        $this->setCompanySetting(TwoFactorService::SETTING_POLICY, $validated['two_factor_policy']);
        $this->setCompanySetting(TwoFactorService::SETTING_DEFAULT_METHOD, $validated['two_factor_default_method']);

        if ($validated['two_factor_policy'] === TwoFactorService::POLICY_OFF && $previousPolicy !== TwoFactorService::POLICY_OFF) {
            $twoFactor->disableForCompany((int) $this->companyId());
        }

        return redirect()->route('settings.index', ['tab' => 'security'])->with('success', 'Security settings saved.');
    }

    public function companyUpdate(Request $request)
    {
        $company = auth()->user()?->company;
        if (! $company) {
            return redirect()->route('settings.index')->with('error', 'Company not found.');
        }
        abort_unless((int) $company->id === (int) auth()->user()->company_id, 403);

        $gstin = $request->input('gstin');
        if ($gstin !== null && trim((string) $gstin) !== '') {
            $request->merge(['gstin' => strtoupper(preg_replace('/\s+/', '', (string) $gstin))]);
        } else {
            $request->merge(['gstin' => null]);
        }

        if ($request->has('short_name')) {
            $request->merge([
                'short_name' => Company::normalizeShortName($request->input('short_name')),
            ]);
        }

        $request->merge(EmployeeValidation::normalize($request->only(['email', 'phone'])));

        $validated = $request->validate([
            'name' => FormTextRules::notNumericOnly(true, 255),
            'short_name' => [
                'nullable',
                'string',
                'max:100',
                Rule::unique('companies', 'short_name')->ignore($company->id),
            ],
            'email' => 'nullable|email|max:255',
            'phone' => 'nullable|digits:10',
            'website' => 'nullable|string|max:255',
            'address' => FormTextRules::notNumericOnly(false, 1000),
            'employee_number_prefix' => ['nullable', 'string', 'max:20', 'regex:/^[A-Za-z0-9_#-]+$/'],
            'employee_number_digits' => ['nullable', 'integer', 'min:1', 'max:10'],
            'gstin' => [
                'nullable',
                'string',
                'size:15',
                'regex:/^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z][1-9A-Z]Z[0-9A-Z]$/',
            ],
        ], array_merge(FormTextRules::messages(), [
            'phone.digits' => EmployeeValidation::messages()['phone.digits'],
        ]));
        if (array_key_exists('short_name', $validated)) {
            $validated['short_name'] = Company::normalizeShortName($validated['short_name']);
        }

        $employeeNumberPrefix = strtoupper(trim((string) ($validated['employee_number_prefix'] ?? null)));
        $employeeNumberDigits = (int) ($validated['employee_number_digits'] ?? 1);
        unset($validated['employee_number_prefix']);
        unset($validated['employee_number_digits']);

        $company->update($validated);
        $existingSequence = DB::table('employee_number_sequences')
            ->where('company_id', (int) $company->id)
            ->first();
        $normalizedPrefix = $employeeNumberPrefix !== '' ? $employeeNumberPrefix : null;
        $normalizedDigits = max(1, min(10, $employeeNumberDigits));

        if ($existingSequence) {
            DB::table('employee_number_sequences')
                ->where('company_id', (int) $company->id)
                ->update([
                    'prefix' => $normalizedPrefix,
                    'digits' => $normalizedDigits,
                    'updated_at' => now(),
                ]);
        } else {
            DB::table('employee_number_sequences')->insert([
                'company_id' => (int) $company->id,
                'prefix' => $normalizedPrefix,
                'digits' => $normalizedDigits,
                'last_number' => 0,
                'created_at' => now(),
                'updated_at' => now(),
            ]);
        }

        return redirect()->route('settings.index', ['tab' => 'general'])->with('success', 'Company details updated successfully.');
    }

    public function home()
    {
        $user = auth()->user();
        $superAdmin = (bool) ($user?->is_superadmin ?? false);
        $can = fn (string $p) => $superAdmin || ($user && $user->hasPermission($p));

        $sidebarModules = config('tenant_modules.sidebar_module', []);
        $allowedMods = $allowedModules ?? null;
        $moduleAllowed = function (string $perm) use ($allowedMods, $sidebarModules) {
            if ($allowedMods === null) {
                return true;
            }
            $mod = $sidebarModules[$perm] ?? null;
            if ($mod === null) {
                return true;
            }

            return in_array($mod, $allowedMods, true);
        };
        $canShow = fn (string $p) => $can($p) && $moduleAllowed($p);

        $tiles = [
            ['title' => 'General', 'desc' => 'Company settings', 'icon' => 'bi-gear', 'route' => 'settings.index', 'params' => ['tab' => 'general'], 'perm' => 'manage_settings'],
            ['title' => 'Audit log', 'desc' => 'Sensitive action history', 'icon' => 'bi-journal-text', 'route' => 'settings.audit', 'perm' => 'manage_settings'],
            ['title' => 'Email', 'desc' => 'SMTP & mail settings', 'icon' => 'bi-envelope', 'route' => 'settings.email', 'perm' => 'manage_settings'],
            ['title' => 'Roles & permissions', 'desc' => 'System and custom roles', 'icon' => 'bi-shield-lock', 'route' => 'tenant-roles.index', 'perm' => 'roles_view'],

            ['title' => 'Departments', 'desc' => 'Org structure setup', 'icon' => 'bi-building', 'route' => 'departments.index', 'perm' => 'users_view'],
            ['title' => 'Designations', 'desc' => 'Job titles & roles', 'icon' => 'bi-award', 'route' => 'designations.index', 'perm' => 'users_view'],
            ['title' => 'Locations', 'desc' => 'Office locations', 'icon' => 'bi-geo-alt', 'route' => 'locations.index', 'perm' => 'users_view'],
            ['title' => 'Attendance Policy', 'desc' => 'Check-in modes, geo-fence & remote', 'icon' => 'bi-geo', 'route' => 'attendance-policy.edit', 'perm' => 'attendances_edit'],
            ['title' => 'Shifts', 'desc' => 'Working hours setup', 'icon' => 'bi-clock', 'route' => 'shifts.index', 'perm' => 'attendances_view'],
            ['title' => 'Weekoff Rules', 'desc' => 'Weekly off patterns', 'icon' => 'bi-calendar-week', 'route' => 'weekoff-rules.index', 'perm' => 'attendances_view'],
            ['title' => 'Biometric Devices', 'desc' => 'ZKTeco webhook & terminals', 'icon' => 'bi-fingerprint', 'route' => 'biometric-devices.index', 'perm' => 'biometric_devices_view'],
            ['title' => 'Attendance Punches', 'desc' => 'Device punch audit log', 'icon' => 'bi-list-check', 'route' => 'attendance-punches.index', 'perm' => 'biometric_devices_view'],

            ['title' => 'Leave Types', 'desc' => 'Leave policies', 'icon' => 'bi-tags', 'route' => 'leave-types.index', 'perm' => 'leaves_view'],
            ['title' => 'Holiday Calendar', 'desc' => 'Company holidays', 'icon' => 'bi-calendar-event', 'route' => 'holidays.index', 'perm' => 'leaves_view'],

            ['title' => 'Payroll Settings', 'desc' => 'PF/ESI/PT config', 'icon' => 'bi-gear-wide-connected', 'route' => 'payroll.index', 'params' => ['tab' => 'setup', 'sub' => 'pf_esi'], 'perm' => 'payrolls_view'],
            ['title' => 'Salary Groups', 'desc' => 'Salary structure', 'icon' => 'bi-people-fill', 'route' => 'salary-groups.index', 'perm' => 'payrolls_view'],
            ['title' => 'Salary Components', 'desc' => 'Earnings & deductions', 'icon' => 'bi-stack', 'route' => 'salary-components.index', 'perm' => 'payrolls_view'],

            ['title' => 'Asset Types', 'desc' => 'Asset category setup', 'icon' => 'bi-tags', 'route' => 'asset-types.index', 'perm' => 'assets_view'],

            ['title' => 'Payees', 'desc' => 'Payee master', 'icon' => 'bi-person-dash', 'route' => 'payees.index', 'perm' => ['finance_treasury_view', 'finance_view']],
            ['title' => 'Payers', 'desc' => 'Payer master', 'icon' => 'bi-person-plus', 'route' => 'payers.index', 'perm' => ['finance_treasury_view', 'finance_view']],
            ['title' => 'Deposit Categories', 'desc' => 'Deposit classification', 'icon' => 'bi-tags', 'route' => 'deposit-categories.index', 'perm' => ['finance_treasury_view', 'finance_view']],
            ['title' => 'Vendors', 'desc' => 'Vendor directory', 'icon' => 'bi-shop', 'route' => 'vendors.index', 'perm' => ['finance_treasury_view', 'finance_view']],

            ['title' => 'Letter Head Templates', 'desc' => 'Letterhead & print', 'icon' => 'bi-file-earmark-richtext', 'route' => 'letter-head-templates.index', 'perm' => 'documents_view'],
            ['title' => 'Forms', 'desc' => 'Form builder', 'icon' => 'bi-ui-checks', 'route' => 'forms.index', 'perm' => 'documents_view'],

            ['title' => 'Company Policies', 'desc' => 'Policy documents', 'icon' => 'bi-shield-check', 'route' => 'company-policies.index', 'perm' => 'hr_operations_view'],
            ['title' => 'Announcements', 'desc' => 'Company updates', 'icon' => 'bi-megaphone', 'route' => 'announcements.index', 'perm' => 'announcements_view'],
            ['title' => 'Reports', 'desc' => 'Analytics & exports', 'icon' => 'bi-bar-chart-line', 'route' => 'reports.index', 'perm' => 'view_reports'],
        ];

        $canShowTile = function (array $tile) use ($canShow): bool {
            $perm = $tile['perm'] ?? '';
            if (is_array($perm)) {
                return collect($perm)->contains(fn (string $p) => $canShow($p));
            }

            return $canShow((string) $perm);
        };

        $tiles = array_values(array_filter($tiles, $canShowTile));

        return view('settings.home', compact('tiles'));
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'key' => 'required|string|max:100',
            'value' => 'nullable|string|max:2000',
        ]);
        CompanySetting::updateOrCreate(
            [
                'company_id' => auth()->user()->company_id,
                'key' => $validated['key'],
            ],
            ['value' => $validated['value'] ?? '']
        );

        return redirect()->route('settings.index')->with('success', 'Setting saved successfully.');
    }

    public function logoStore(Request $request)
    {
        $request->validate([
            'logo' => 'required|image|mimes:png,jpg,jpeg,webp|max:2048',
        ]);

        $company = auth()->user()?->company;
        if (! $company) {
            return redirect()->route('settings.index')->with('error', 'Company not found.');
        }

        $oldLogo = $company->logo;
        $logoPath = $request->file('logo')->store('company-logos', 'public');
        $company->logo = $logoPath;
        $company->save();

        if ($oldLogo && $oldLogo !== $logoPath && Storage::disk('public')->exists($oldLogo)) {
            Storage::disk('public')->delete($oldLogo);
        }

        return redirect()->route('settings.index', ['tab' => 'branding'])->with('success', 'Company logo updated successfully.');
    }

    public function logoDestroy()
    {
        $company = auth()->user()?->company;
        if (! $company) {
            return redirect()->route('settings.index')->with('error', 'Company not found.');
        }

        $oldLogo = $company->logo;
        $company->logo = null;
        $company->save();

        if ($oldLogo && Storage::disk('public')->exists($oldLogo)) {
            Storage::disk('public')->delete($oldLogo);
        }

        return redirect()->route('settings.index', ['tab' => 'branding'])->with('success', 'Company logo removed successfully.');
    }

    public function emailIndex()
    {
        $mail = [
            'mail_mailer' => $this->getCompanySetting('mail_mailer', config('mail.default', 'smtp')),
            'mail_from_name' => $this->getCompanySetting('mail_from_name', config('mail.from.name', config('app.name'))),
            'mail_from_address' => $this->getCompanySetting('mail_from_address', config('mail.from.address', '')),
            'mail_host' => $this->getCompanySetting('mail_host', config('mail.mailers.smtp.host', '')),
            'mail_port' => $this->getCompanySetting('mail_port', config('mail.mailers.smtp.port', '587')),
            'mail_encryption' => $this->getCompanySetting('mail_encryption', config('mail.mailers.smtp.encryption', 'tls')),
            'mail_username' => $this->getCompanySetting('mail_username', ''),
            'mail_password' => $this->getCompanySetting('mail_password', ''),
            'mail_queue' => $this->getCompanySetting('mail_queue', 'no'),
        ];
        $hasPassword = (bool) $this->getCompanySetting('mail_password');

        return view('settings.email', compact('mail', 'hasPassword'));
    }

    public function emailStore(Request $request)
    {
        $request->validate([
            'mail_mailer' => 'required|string|in:smtp,log',
            'mail_from_name' => 'required|string|max:255',
            'mail_from_address' => 'required|email',
            'mail_host' => 'nullable|string|max:255',
            'mail_port' => 'nullable|string|max:20',
            'mail_encryption' => 'nullable|string|in:tls,ssl,null',
            'mail_username' => 'nullable|string|max:255',
            'mail_password' => 'nullable|string|max:255',
            'mail_queue' => 'nullable|string|in:yes,no',
        ]);
        $this->setCompanySetting('mail_mailer', $request->mail_mailer);
        $this->setCompanySetting('mail_from_name', $request->mail_from_name);
        $this->setCompanySetting('mail_from_address', $request->mail_from_address);
        $this->setCompanySetting('mail_host', $request->mail_host ?? '');
        $this->setCompanySetting('mail_port', $request->mail_port ?? '587');
        $this->setCompanySetting('mail_encryption', $request->mail_encryption ?? 'tls');
        $this->setCompanySetting('mail_username', $request->mail_username ?? '');
        if ($request->filled('mail_password')) {
            $this->setCompanySetting('mail_password', $request->mail_password);
        }
        $this->setCompanySetting('mail_queue', $request->mail_queue ?? 'no');

        return redirect()->route('settings.email')->with('success', 'Email settings updated.');
    }

    public function emailTestMail(Request $request)
    {
        $request->validate(['to' => 'required|email']);
        $to = $request->to;
        $companyId = $this->companyId();
        try {
            if ($companyId) {
                TenantMailConfig::applyForCompany($companyId, function () use ($to) {
                    Mail::raw('This is a test email from your company HRMS. If you received this, your SMTP settings are working.', function ($message) use ($to) {
                        $message->to($to)->subject('Test email – '.config('app.name'));
                    });
                });
            } else {
                Mail::raw('This is a test email from your company HRMS.', function ($message) use ($to) {
                    $message->to($to)->subject('Test email – '.config('app.name'));
                });
            }

            return redirect()->route('settings.email')->with('success', 'Test email sent to '.$to);
        } catch (\Throwable $e) {
            return redirect()->route('settings.email')->with('error', 'Failed to send test email: '.$e->getMessage());
        }
    }

    public function profileIndex()
    {
        $user = auth()->user();
        $user->load(['department', 'designation', 'location', 'shift', 'reportingManager']);
        $twoFactor = app(TwoFactorService::class);
        $intro = UserProfileIntro::query()->firstOrCreate(['user_id' => $user->id]);
        $quickLinks = $this->normalizeQuickLinks($intro->quick_links);
        $profileCompletion = $this->profileCompletionPercent($user, $intro);

        $twoFactorPolicy = $twoFactor->companyPolicy($user);
        $twoFactorOffered = $twoFactor->isOfferedByCompany($user);

        $profileNavSections = [
            ['id' => 'account', 'label' => 'Account', 'icon' => 'bi-person-circle'],
            ['id' => 'basic', 'label' => 'Basic Info', 'icon' => 'bi-person-vcard'],
            ['id' => 'work', 'label' => 'Work Info', 'icon' => 'bi-briefcase'],
            ['id' => 'bank', 'label' => 'Bank Account Details', 'icon' => 'bi-bank'],
        ];
        if ($twoFactorOffered) {
            $profileNavSections[] = ['id' => 'security', 'label' => 'Security', 'icon' => 'bi-shield-lock'];
        }
        if ($user->canManageEmailNotificationPreferences()) {
            $profileNavSections[] = ['id' => 'notifications', 'label' => 'Notifications', 'icon' => 'bi-bell'];
        }
        $profileNavSections[] = ['id' => 'about', 'label' => 'About you', 'icon' => 'bi-chat-square-text'];

        return view('settings.profile', [
            'user' => $user,
            'intro' => $intro,
            'quickLinks' => $quickLinks,
            'profileCompletion' => $profileCompletion,
            'notificationCategories' => config('hrms_notifications.categories', []),
            'emailNotificationPrefs' => $user->notification_preferences['email'] ?? [],
            'showEmailNotifications' => $user->canManageEmailNotificationPreferences(),
            'totpProvisioningUri' => $twoFactor->totpProvisioningUri($user),
            'sessions' => UserSession::where('user_id', $user->id)->orderByDesc('last_activity_at')->limit(10)->get(),
            'profileNavSections' => $profileNavSections,
            'twoFactorOffered' => $twoFactorOffered,
            'twoFactorPolicy' => $twoFactorPolicy,
            'twoFactorRequired' => $twoFactor->isRequiredByCompany($user),
            'canDisableTwoFactor' => $twoFactor->canDisable($user),
            'mustEnrollTwoFactor' => $twoFactor->mustEnroll($user),
        ]);
    }

    public function profileUpdate(Request $request)
    {
        $user = auth()->user();
        $rules = [
            'name' => ['required', 'string', 'max:255', 'regex:'.EmployeeValidation::ALPHA_SPACES],
            'email' => [
                'required',
                'email',
                'max:255',
                Rule::unique('users', 'email')
                    ->ignore($user->id)
                    ->where(fn ($q) => $user->company_id
                        ? $q->where('company_id', $user->company_id)
                        : $q->whereNull('company_id')),
            ],
            'profile_photo' => 'nullable|image|mimes:jpg,jpeg,png,webp|max:2048',
            'notification_email' => 'nullable|array',
            'notification_email.*' => 'nullable|boolean',
        ];
        if ($request->filled('password')) {
            $rules['password'] = ['required', 'confirmed', Password::defaults()];
        }
        $request->merge(EmployeeValidation::normalize($request->only(['email'])));
        $data = $request->validate($rules, EmployeeValidation::messages());
        $user->name = $data['name'];
        $user->email = strtolower($data['email']);
        if (! empty($data['password'] ?? null)) {
            $user->password = Hash::make($data['password']);
        }
        if ($request->hasFile('profile_photo')) {
            $oldPhoto = $user->profile_photo;
            $newPhotoPath = $request->file('profile_photo')->store('profile-photos', 'public');
            $user->profile_photo = $newPhotoPath;

            if (
                $oldPhoto &&
                ! str_starts_with($oldPhoto, 'http://') &&
                ! str_starts_with($oldPhoto, 'https://') &&
                $oldPhoto !== $newPhotoPath &&
                Storage::disk('public')->exists($oldPhoto)
            ) {
                Storage::disk('public')->delete($oldPhoto);
            }
        }
        $user->save();

        if ($request->has('notification_email') && $user->canManageEmailNotificationPreferences()) {
            $emailPrefs = [];
            foreach (array_keys(config('hrms_notifications.categories', [])) as $category) {
                $emailPrefs[$category] = $request->boolean('notification_email.'.$category);
            }
            $user->mergeNotificationPreferences(['email' => $emailPrefs]);
        }

        $fragment = ($request->has('notification_email') && $user->canManageEmailNotificationPreferences())
            ? '#notifications'
            : '#account';

        return redirect()->to(route('settings.profile').$fragment)->with('success', 'Profile updated.');
    }

    public function updateProfileBasic(Request $request)
    {
        $user = auth()->user();
        $request->merge(EmployeeValidation::normalize($request->only(['phone', 'pan_number'])));
        $validated = $request->validate(
            EmployeeValidation::profileBasicRules(),
            EmployeeValidation::messages()
        );

        $writable = $this->filterUnlockedProfileFields($user, $validated, [
            'phone', 'gender', 'dob', 'father_name', 'pan_number',
        ]);

        if ($writable !== []) {
            $user->update($writable);
        }

        return redirect()->to(route('settings.profile').'#basic')->with('success', 'Basic information updated.');
    }

    public function updateProfileWork(Request $request)
    {
        $user = auth()->user();
        $validated = $request->validate(
            EmployeeValidation::profileWorkRules(),
            EmployeeValidation::messages()
        );

        $writable = $this->filterUnlockedProfileFields($user, $validated, [
            'uan_number', 'work_state', 'pt_location',
        ]);

        if ($writable !== []) {
            $user->update($writable);
        }

        return redirect()->to(route('settings.profile').'#work')->with('success', 'Work information updated.');
    }

    public function updateProfileBank(Request $request)
    {
        $user = auth()->user();
        $validated = $request->validate(
            EmployeeValidation::profileBankRules(),
            EmployeeValidation::messages()
        );

        $writable = $this->filterUnlockedProfileFields($user, $validated, [
            'account_holder_name', 'bank_name', 'account_number', 'branch_name', 'city', 'ifsc_code',
        ]);

        if ($writable !== []) {
            $user->update($writable);
        }

        return redirect()->to(route('settings.profile').'#bank')->with('success', 'Bank details updated.');
    }

    public function enableTwoFactor(TwoFactorService $twoFactor)
    {
        $user = auth()->user();

        if (! $twoFactor->isOfferedByCompany($user)) {
            return redirect()->to(route('settings.profile').'#security')->with('error', 'Two-factor authentication is disabled for your company.');
        }

        $twoFactor->enableEmail($user);

        return redirect()->to(route('settings.profile').'#security')->with('success', 'Two-factor authentication enabled. You will receive an email code on each login.');
    }

    public function enableTotpTwoFactor(TwoFactorService $twoFactor)
    {
        $user = auth()->user();

        if (! $twoFactor->isOfferedByCompany($user)) {
            return redirect()->to(route('settings.profile').'#security')->with('error', 'Two-factor authentication is disabled for your company.');
        }

        $secret = $twoFactor->enableTotp($user);

        return redirect()->to(route('settings.profile').'#security')->with([
            'success' => 'Authenticator app 2FA enabled. Scan the QR URI or enter the secret manually.',
            'totp_secret' => $secret,
        ]);
    }

    public function disableTwoFactor(Request $request, TwoFactorService $twoFactor)
    {
        $request->validate(['password' => 'required|string']);
        $user = auth()->user();

        if (! $twoFactor->canDisable($user)) {
            return redirect()->to(route('settings.profile').'#security')->with('error', 'Your company requires two-factor authentication. It cannot be disabled.');
        }

        if (! Hash::check($request->password, $user->password)) {
            return redirect()->to(route('settings.profile').'#security')->withErrors(['password' => 'Current password is incorrect.']);
        }

        $twoFactor->disable($user);

        return redirect()->to(route('settings.profile').'#security')->with('success', 'Two-factor authentication disabled.');
    }

    public function updateSelfIntro(Request $request)
    {
        $user = auth()->user();

        $validated = $request->validate([
            'about' => ['nullable', 'string', 'max:2000'],
            'job_love' => ['nullable', 'string', 'max:2000'],
            'interests_hobbies' => ['nullable', 'string', 'max:2000'],
            'past_experience' => ['nullable', 'string', 'max:2000'],
            'quick_links' => ['nullable', 'array', 'max:6'],
            'quick_links.linkedin' => 'nullable|url|max:255',
            'quick_links.instagram' => 'nullable|url|max:255',
            'quick_links.facebook' => 'nullable|url|max:255',
        ]);

        UserProfileIntro::query()->updateOrCreate(
            ['user_id' => $user->id],
            [
                'about' => $validated['about'] ?? null,
                'job_love' => $validated['job_love'] ?? null,
                'interests_hobbies' => $validated['interests_hobbies'] ?? null,
                'past_experience' => $validated['past_experience'] ?? null,
                'quick_links' => [
                    'linkedin' => $this->normalizeQuickLinkValue(data_get($validated, 'quick_links.linkedin')),
                    'instagram' => $this->normalizeQuickLinkValue(data_get($validated, 'quick_links.instagram')),
                    'facebook' => $this->normalizeQuickLinkValue(data_get($validated, 'quick_links.facebook')),
                ],
            ]
        );

        return redirect()->to(route('settings.profile').'#about')->with('success', 'Profile updated.');
    }

    private function normalizeQuickLinks(mixed $quickLinks): array
    {
        $links = is_array($quickLinks) ? $quickLinks : [];

        // Backward compatibility: previous shape stored a numeric array.
        if (array_is_list($links)) {
            $links = [
                'linkedin' => $links[0] ?? null,
                'instagram' => $links[1] ?? null,
                'facebook' => $links[2] ?? null,
            ];
        }

        return [
            'linkedin' => $this->normalizeQuickLinkValue($links['linkedin'] ?? null),
            'instagram' => $this->normalizeQuickLinkValue($links['instagram'] ?? null),
            'facebook' => $this->normalizeQuickLinkValue($links['facebook'] ?? null),
        ];
    }

    private function normalizeQuickLinkValue(mixed $value): ?string
    {
        $trimmed = trim((string) ($value ?? ''));

        return $trimmed !== '' ? $trimmed : null;
    }

    private function profileCompletionPercent(User $user, ?UserProfileIntro $intro): int
    {
        $signals = [
            ! empty($user->profile_photo),
            ! empty($user->phone),
            ! empty($user->dob),
            ! empty($user->joining_date),
            ! empty($user->department_id),
            ! empty($user->designation_id),
            ! empty($intro?->about),
            ! empty($intro?->job_love),
            ! empty($intro?->interests_hobbies),
            ! empty($intro?->past_experience),
        ];

        $completed = count(array_filter($signals, fn (bool $value): bool => $value));
        $total = max(1, count($signals));

        return (int) round(($completed / $total) * 100);
    }

    public function exportPersonalData()
    {
        $user = auth()->user();
        $payload = [
            'exported_at' => now()->toIso8601String(),
            'profile' => $user->only([
                'id', 'name', 'email', 'phone', 'employee_number', 'joining_date',
                'last_working_date', 'status', 'created_at',
            ]),
            'department' => $user->department?->only(['id', 'name']),
            'designation' => $user->designation?->only(['id', 'name']),
            'notification_preferences' => $user->notification_preferences,
        ];

        $filename = 'my-data-'.$user->id.'-'.now()->format('Ymd').'.json';

        return response()->streamDownload(function () use ($payload) {
            echo json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
        }, $filename, ['Content-Type' => 'application/json']);
    }

    public function revokeSession(UserSession $userSession, UserSessionService $sessions)
    {
        abort_unless((int) $userSession->user_id === (int) auth()->id(), 403);
        $sessions->revoke($userSession);

        return redirect()->to(route('settings.profile').'#security')->with('success', 'Session revoked.');
    }

    private function filterUnlockedProfileFields(User $user, array $data, array $fields): array
    {
        $writable = [];
        foreach ($fields as $field) {
            if (! array_key_exists($field, $data)) {
                continue;
            }
            if ($this->profileFieldIsEmpty($user, $field)) {
                $writable[$field] = $data[$field];
            }
        }

        return $writable;
    }

    private function profileFieldIsEmpty(User $user, string $field): bool
    {
        $current = $user->{$field};

        if ($current === null) {
            return true;
        }

        if ($current instanceof CarbonInterface) {
            return false;
        }

        return trim((string) $current) === '';
    }
}
