<?php

namespace App\Livewire;

use App\Models\Budget;
use App\Models\Debt;
use App\Models\Goal;
use App\Models\ResourceShare;
use App\Models\SubscriptionItem;
use App\Models\Transaction;
use App\Models\UsageCounter;
use App\Services\FinanceRepository;
use App\Services\PreferencesStore;
use App\Support\LocaleOptions;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rule;
use Livewire\Attributes\Layout;
use Livewire\Component;

#[Layout('layouts.app')]
class SettingsPage extends Component
{
    public string $activeSection = 'account';

    /** @var array{displayName: string, email: string, password: string} */
    public array $accountDraft = [
        'displayName' => '',
        'email' => '',
        'password' => '••••••••••••',
    ];

    /** @var array{currentPassword: string, newPassword: string, newPasswordConfirmation: string} */
    public array $passwordDraft = [
        'currentPassword' => '',
        'newPassword' => '',
        'newPasswordConfirmation' => '',
    ];

    /** @var array{firstName: string, lastName: string, phone: string, timezone: string} */
    public array $profileDraft = [
        'firstName' => '',
        'lastName' => '',
        'phone' => '',
        'timezone' => '',
    ];

    public float $profileMonthlyIncome = 0.0;

    public float $profileMonthlyLimit = 0.0;

    public float $profileSavingsGoal = 0.0;

    public string $dangerConfirmation = '';

    public function mount(): void
    {
        $this->syncAccountDraft();
        $this->syncProfileDraft();
        $this->applySectionFromQuery();
    }

    public static function initials(string $displayName): string
    {
        $parts = array_values(array_filter(preg_split('/\s+/u', trim($displayName)) ?: [], fn ($p) => $p !== ''));
        $slice = array_slice($parts, 0, 2);
        $out = '';
        foreach ($slice as $p) {
            $out .= mb_strtoupper(mb_substr((string) $p, 0, 1));
        }

        return $out !== '' ? $out : 'BU';
    }

    private function applySectionFromQuery(): void
    {
        $allowed = ['account', 'notifications', 'currency', 'appearance', 'privacy', 'export'];
        $q = request()->query('section');
        if (is_string($q) && in_array($q, $allowed, true)) {
            $this->activeSection = $q;
        }
    }

    private function syncProfileDraft(): void
    {
        $p = PreferencesStore::all();
        $prof = $p['profile'] ?? [];
        $this->profileDraft = [
            'firstName' => (string) ($prof['firstName'] ?? ''),
            'lastName' => (string) ($prof['lastName'] ?? ''),
            'phone' => (string) ($prof['phone'] ?? ''),
            'timezone' => (string) ($prof['timezone'] ?? ''),
        ];
        $this->profileMonthlyIncome = (float) ($prof['monthlyIncome'] ?? 0);
        $this->profileMonthlyLimit = (float) ($prof['monthlyLimit'] ?? 0);
        $this->profileSavingsGoal = (float) ($prof['savingsGoal'] ?? 0);
    }

    private function syncAccountDraft(): void
    {
        $user = auth()->user();
        $p = PreferencesStore::all();
        $this->accountDraft = [
            'displayName' => (string) ($user?->name ?? ($p['profile']['displayName'] ?? '')),
            'email' => (string) ($user?->email ?? ($p['profile']['email'] ?? '')),
            'password' => '••••••••••••',
        ];
    }

    public function setActiveSection(string $id): void
    {
        $this->activeSection = $id;
    }

    public static function resolvedThemeLabel(string $theme): string
    {
        return match ($theme) {
            'system' => (string) __('budgets.settings_page.appearance.theme_system'),
            'dark' => (string) __('budgets.settings_page.appearance.theme_dark'),
            default => (string) __('budgets.settings_page.appearance.theme_light'),
        };
    }

    public static function regionSummary(array $p): string
    {
        $cur = (string) ($p['regional']['currency'] ?? 'EUR');
        $region = (string) ($p['regional']['region'] ?? '');
        $first = explode('/', $region)[0] ?? $region;

        return $cur.' · '.$first;
    }

    private function monthlySpendTotal(): float
    {
        $sum = 0.0;
        foreach (app(FinanceRepository::class)->transactions() as $t) {
            if (($t['type'] ?? '') === 'expense') {
                $sum += abs((float) ($t['amount'] ?? 0));
            }
        }

        return $sum;
    }

    /** @return list<array{id: string, icon: string, label: string, desc: string, summary: string}> */
    private function sectionMeta(array $p): array
    {
        $n = $p['notifications'] ?? [];
        $freq = (string) ($n['digestFrequency'] ?? 'weekly');
        if (! in_array($freq, ['daily', 'weekly', 'monthly'], true)) {
            $freq = 'weekly';
        }
        $digestPhrase = (string) __('budgets.settings_page.digest_phrase_'.$freq);
        $lead = (int) ($n['reminderLeadDays'] ?? 3);
        $remSuffix = $lead === 1
            ? (string) __('budgets.settings_page.reminder_one', ['count' => $lead])
            : (string) __('budgets.settings_page.reminder_other', ['count' => $lead]);
        $notifDesc = $digestPhrase.' · '.$remSuffix;

        $twoFa = ! empty($p['privacy']['twoFactorEnabled'])
            ? (string) __('budgets.settings_page.two_fa_on')
            : (string) __('budgets.settings_page.two_fa_off');
        $timeout = (int) ($p['privacy']['sessionTimeoutMinutes'] ?? 30);
        $privacyDesc = $twoFa.' · '.(string) __('budgets.settings_page.session_timeout_desc', ['minutes' => $timeout]);

        $exportCharts = ! empty($p['exports']['includeCharts']);
        $exportPart = $exportCharts
            ? (string) __('budgets.settings_page.export_desc_charts')
            : (string) __('budgets.settings_page.export_desc_data_only');
        $exportDesc = strtoupper((string) ($p['exports']['defaultFormat'] ?? 'pdf')).' · '.$exportPart;

        return [
            [
                'id' => 'account',
                'icon' => 'user',
                'label' => (string) __('budgets.settings_page.sections.account.label'),
                'desc' => ($p['profile']['displayName'] ?? '').' · '.($p['profile']['email'] ?? ''),
                'summary' => (string) __('budgets.settings_page.sections.account.summary'),
            ],
            [
                'id' => 'notifications',
                'icon' => 'bell',
                'label' => (string) __('budgets.settings_page.sections.notifications.label'),
                'desc' => $notifDesc,
                'summary' => (string) __('budgets.settings_page.sections.notifications.summary'),
            ],
            [
                'id' => 'currency',
                'icon' => 'globe',
                'label' => (string) __('budgets.settings_page.sections.currency.label'),
                'desc' => self::regionSummary($p),
                'summary' => (string) __('budgets.settings_page.sections.currency.summary'),
            ],
            [
                'id' => 'appearance',
                'icon' => 'palette',
                'label' => (string) __('budgets.settings_page.sections.appearance.label'),
                'desc' => self::resolvedThemeLabel((string) ($p['appearance']['theme'] ?? 'light')).' '.(string) __('budgets.settings_page.theme_suffix'),
                'summary' => (string) __('budgets.settings_page.sections.appearance.summary'),
            ],
            [
                'id' => 'privacy',
                'icon' => 'shield',
                'label' => (string) __('budgets.settings_page.sections.privacy.label'),
                'desc' => $privacyDesc,
                'summary' => (string) __('budgets.settings_page.sections.privacy.summary'),
            ],
            [
                'id' => 'export',
                'icon' => 'download',
                'label' => (string) __('budgets.settings_page.sections.export.label'),
                'desc' => $exportDesc,
                'summary' => (string) __('budgets.settings_page.sections.export.summary'),
            ],
        ];
    }

    public function saveAccount(): void
    {
        $user = auth()->user();
        if ($user === null) {
            return;
        }

        $validated = $this->validate([
            'accountDraft.displayName' => ['required', 'string', 'max:255'],
            'accountDraft.email' => ['required', 'email', 'max:255', Rule::unique('users', 'email')->ignore($user->id)],
            'profileDraft.firstName' => ['nullable', 'string', 'max:120'],
            'profileDraft.lastName' => ['nullable', 'string', 'max:120'],
            'profileDraft.phone' => ['nullable', 'string', 'max:50'],
            'profileDraft.timezone' => ['nullable', 'string', 'max:80'],
            'profileMonthlyIncome' => ['nullable', 'numeric', 'min:0'],
            'profileMonthlyLimit' => ['nullable', 'numeric', 'min:0'],
            'profileSavingsGoal' => ['nullable', 'numeric', 'min:0'],
        ]);

        $this->profileDraft = $validated['profileDraft'];
        $this->profileMonthlyIncome = (float) ($validated['profileMonthlyIncome'] ?? 0);
        $this->profileMonthlyLimit = (float) ($validated['profileMonthlyLimit'] ?? 0);
        $this->profileSavingsGoal = (float) ($validated['profileSavingsGoal'] ?? 0);

        $first = trim((string) ($this->profileDraft['firstName'] ?? ''));
        $last = trim((string) ($this->profileDraft['lastName'] ?? ''));
        $combined = trim($first.' '.$last);
        $fallbackDisplay = trim((string) $validated['accountDraft']['displayName']);
        $displayName = $combined !== '' ? $combined : $fallbackDisplay;
        if ($displayName === '') {
            $displayName = (string) $user->name;
        }
        $email = (string) $validated['accountDraft']['email'];

        $emailChanged = strtolower($email) !== strtolower((string) $user->email);
        $user->name = $displayName;
        $user->email = $email;
        if ($emailChanged) {
            $user->email_verified_at = null;
        }
        $user->save();

        PreferencesStore::update(function (array $p) use ($displayName, $email, $first, $last) {
            $p['profile'] = array_replace_recursive($p['profile'] ?? [], $this->profileDraft, [
                'displayName' => $displayName,
                'email' => $email,
                'firstName' => $first,
                'lastName' => $last,
                'monthlyIncome' => $this->profileMonthlyIncome,
                'monthlyLimit' => $this->profileMonthlyLimit,
                'savingsGoal' => $this->profileSavingsGoal,
            ]);

            return $p;
        });

        $this->syncAccountDraft();
        $this->syncProfileDraft();

        session()->flash('toast', (string) __('budgets.settings_page.toast_account_saved'));
    }

    public function changePassword(): void
    {
        $user = auth()->user();
        if ($user === null) {
            return;
        }

        $validated = $this->validate([
            'passwordDraft.currentPassword' => ['required', 'string'],
            'passwordDraft.newPassword' => ['required', 'string', 'min:8', 'different:passwordDraft.currentPassword'],
            'passwordDraft.newPasswordConfirmation' => ['required', 'same:passwordDraft.newPassword'],
        ]);

        if (! Hash::check((string) $validated['passwordDraft']['currentPassword'], (string) $user->password)) {
            $this->addError('passwordDraft.currentPassword', (string) __('budgets.settings_page.password_current_invalid'));

            return;
        }

        $user->password = (string) $validated['passwordDraft']['newPassword'];
        $user->save();

        $this->passwordDraft = [
            'currentPassword' => '',
            'newPassword' => '',
            'newPasswordConfirmation' => '',
        ];

        session()->flash('toast', (string) __('budgets.settings_page.toast_password_reset'));
    }

    public function resetAll(): void
    {
        PreferencesStore::reset();
        $this->syncAccountDraft();
        $this->syncProfileDraft();
        session()->flash('toast', (string) __('budgets.settings_page.toast_reset'));
    }

    public function clearAllData(): void
    {
        $user = auth()->user();
        if ($user === null) {
            return;
        }

        $validated = $this->validate([
            'dangerConfirmation' => ['required', 'in:DELETE'],
        ]);

        if (! isset($validated['dangerConfirmation'])) {
            return;
        }

        DB::transaction(function () use ($user): void {
            Transaction::query()->where('user_id', $user->id)->delete();
            Budget::query()->where('user_id', $user->id)->delete();
            Goal::query()->where('user_id', $user->id)->delete();
            Debt::query()->where('user_id', $user->id)->delete();
            SubscriptionItem::query()->where('user_id', $user->id)->delete();
            ResourceShare::query()
                ->where('owner_user_id', $user->id)
                ->orWhere('shared_with_user_id', $user->id)
                ->delete();
            UsageCounter::query()->where('user_id', $user->id)->delete();

            PreferencesStore::reset();
        });

        $this->dangerConfirmation = '';
        session()->flash('toast', (string) __('budgets.settings_page.toast_data_cleared'));
        $this->redirect(route('onboarding'), navigate: true);
    }

    public function deleteAccount(): void
    {
        $user = auth()->user();
        if ($user === null) {
            return;
        }

        $validated = $this->validate([
            'dangerConfirmation' => ['required', 'in:DELETE'],
        ]);

        if (! isset($validated['dangerConfirmation'])) {
            return;
        }

        Auth::logout();

        DB::transaction(function () use ($user): void {
            $user->delete();
        });

        if (request()->hasSession()) {
            request()->session()->invalidate();
            request()->session()->regenerateToken();
        }
        PreferencesStore::forgetMemo();

        $this->dangerConfirmation = '';
        session()->flash('toast', (string) __('budgets.settings_page.toast_account_deleted'));
        $this->redirect(route('home'), navigate: true);
    }

    public function exportData(string $format): void
    {
        $format = strtolower($format) === 'csv' ? 'csv' : 'pdf';
        PreferencesStore::update(function (array $p) use ($format) {
            $p['exports']['defaultFormat'] = $format;
            $p['exports']['lastExportAt'] = (new \DateTimeImmutable('now'))->format(\DateTimeInterface::ATOM);

            return $p;
        });

        session()->flash('toast', (string) __('budgets.settings_page.toast_export', ['format' => strtoupper($format)]));
    }

    public function setNotif(string $key, bool $on): void
    {
        PreferencesStore::update(function (array $p) use ($key, $on) {
            $p = array_replace_recursive($p, ['notifications' => [$key => $on]]);
            if ($key === 'pushNotifications') {
                $p['notifications']['pushPromptState'] = $on ? 'pending' : 'never';
            }

            return $p;
        });
    }

    public function setDigestFrequency(string $value): void
    {
        PreferencesStore::update(fn (array $p) => array_replace_recursive($p, [
            'notifications' => ['digestFrequency' => $value],
        ]));
    }

    public function setReminderLead(int $days): void
    {
        $days = max(1, min(7, $days));
        PreferencesStore::update(fn (array $p) => array_replace_recursive($p, [
            'notifications' => ['reminderLeadDays' => $days],
        ]));
    }

    public function setRegional(string $key, string $value): void
    {
        PreferencesStore::update(fn (array $p) => array_replace_recursive($p, [
            'regional' => [$key => $value],
        ]));
    }

    public function setLanguage(string $lang): void
    {
        $lang = LocaleOptions::normalizeOrFallback($lang);
        session(['budgets.language' => $lang]);
        app()->setLocale($lang);
        PreferencesStore::update(fn (array $p) => array_replace_recursive($p, [
            'regional' => ['language' => $lang],
        ]));
    }

    public function setTheme(string $theme): void
    {
        PreferencesStore::update(fn (array $p) => array_replace_recursive($p, [
            'appearance' => ['theme' => $theme],
        ]));
    }

    public function setAppearanceBool(string $key, bool $on): void
    {
        PreferencesStore::update(fn (array $p) => array_replace_recursive($p, [
            'appearance' => [$key => $on],
        ]));
    }

    public function setDashboardDensity(string $value): void
    {
        PreferencesStore::update(fn (array $p) => array_replace_recursive($p, [
            'appearance' => ['dashboardDensity' => $value],
        ]));
    }

    public function setPrivacyBool(string $key, bool $on): void
    {
        PreferencesStore::update(fn (array $p) => array_replace_recursive($p, [
            'privacy' => [$key => $on],
        ]));
    }

    public function setSessionTimeout(int $minutes): void
    {
        $allowed = [15, 30, 45, 60];
        if (! in_array($minutes, $allowed, true)) {
            $minutes = 30;
        }
        PreferencesStore::update(fn (array $p) => array_replace_recursive($p, [
            'privacy' => ['sessionTimeoutMinutes' => $minutes],
        ]));
    }

    public function setExportBool(string $key, bool $on): void
    {
        PreferencesStore::update(fn (array $p) => array_replace_recursive($p, [
            'exports' => [$key => $on],
        ]));
    }

    public function setDefaultExportFormat(string $value): void
    {
        PreferencesStore::update(fn (array $p) => array_replace_recursive($p, [
            'exports' => ['defaultFormat' => $value],
        ]));
    }

    public function toastPasswordReset(): void
    {
        $this->activeSection = 'account';
    }

    public function toastLogout(): void
    {
        Auth::guard('web')->logout();
        request()->session()->invalidate();
        request()->session()->regenerateToken();
        $this->redirect(route('home'), navigate: true);
    }

    public function render()
    {
        $preferences = PreferencesStore::all();
        $user = auth()->user();
        if ($user !== null) {
            $preferences['profile']['displayName'] = (string) $user->name;
            $preferences['profile']['email'] = (string) $user->email;
        }

        return view('livewire.settings-page', [
            'preferences' => $preferences,
            'sections' => $this->sectionMeta($preferences),
            'monthlySpend' => $this->monthlySpendTotal(),
        ])->title((string) __('budgets.settings_page.title'));
    }
}
