import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

import '../../../../api/marianumcloud/cloud_users/cloud_users_actions.dart';
import '../../../../api/marianumconnect/queries/auth_logout/auth_logout.dart';
import '../../../../model/account_data.dart';
import '../../../../push/push_registration.dart';
import '../../../../routing/app_routes.dart';
import '../../../../state/app/modules/account/bloc/account_bloc.dart';
import '../../../../state/app/modules/account/bloc/account_state.dart';
import '../../../../widget/app_progress_indicator.dart';
import '../../../../widget/async_action_button.dart';
import '../../../../widget/avatar_actions_sheet.dart';
import '../../../../widget/confirm_dialog.dart';
import '../../../../widget/demo_restricted.dart';
import '../../../../widget/user_avatar.dart';

// Display-name is process-wide stable until the user logs out; cache it so
// every Settings rebuild doesn't re-issue the OCS request.
String? _cachedDisplayName;

class AccountSection extends StatefulWidget {
  const AccountSection({super.key});

  @override
  State<AccountSection> createState() => _AccountSectionState();
}

class _AccountSectionState extends State<AccountSection> {
  int _avatarVersion = 0;
  bool _avatarBusy = false;
  String? _displayName = _cachedDisplayName;

  @override
  void initState() {
    super.initState();
    if (_displayName == null) _loadDisplayName();
  }

  Future<void> _loadDisplayName() async {
    try {
      final info = await GetUserInfo().run();
      _cachedDisplayName = info.displayName.isEmpty
          ? null
          : info.displayName;
      if (!mounted) return;
      setState(() => _displayName = _cachedDisplayName);
    } catch (_) {
      // Silent fallback to username — surfacing an error dialog over the
      // settings screen on every open would be noisier than helpful.
    }
  }

  Future<void> _editAvatar() async {
    if (guardDemoAction(context)) return;
    final result = await showAvatarActionsSheet(context, allowRemove: true);
    if (result == null || !mounted) return;

    if (result is AvatarRemoveResult) {
      var confirmed = false;
      await showDialog<void>(
        context: context,
        builder: (_) => ConfirmDialog(
          title: 'Profilbild entfernen',
          content: 'Möchtest du dein Profilbild wirklich entfernen?',
          confirmButton: 'Entfernen',
          onConfirm: () => confirmed = true,
        ),
      );
      if (!confirmed || !mounted) return;
    }

    setState(() => _avatarBusy = true);
    final ok = await runWithErrorDialog(context, () async {
      if (result is AvatarUploadResult) {
        await SetUserAvatar(result.bytes).run();
      } else {
        await DeleteUserAvatar().run();
      }
    });
    if (!mounted) return;
    setState(() => _avatarBusy = false);
    if (!ok) return;

    invalidateAvatarCache(id: AccountData().getUsername(), isGroup: false);
    setState(() => _avatarVersion++);
  }

  @override
  Widget build(BuildContext context) {
    final username = AccountData().getUsername();
    final displayName = _displayName;
    final theme = Theme.of(context);

    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Padding(
          padding: const EdgeInsets.fromLTRB(16, 20, 16, 16),
          child: Row(
            children: [
              SizedBox(
                width: 84,
                height: 84,
                child: Stack(
                  clipBehavior: Clip.none,
                  children: [
                    Center(
                      child: GestureDetector(
                        onTap: () =>
                            AppRoutes.openLargeProfilePicture(context, username),
                        child: UserAvatar(
                          key: ValueKey(_avatarVersion),
                          id: username,
                          size: 36,
                          requestSize: 256,
                        ),
                      ),
                    ),
                    Positioned(
                      right: 0,
                      bottom: 0,
                      child: _AvatarEditBadge(
                        busy: _avatarBusy,
                        onTap: _avatarBusy ? null : _editAvatar,
                      ),
                    ),
                  ],
                ),
              ),
              const SizedBox(width: 16),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Text(
                      displayName ?? username,
                      style: const TextStyle(
                        fontSize: 20,
                        fontWeight: FontWeight.w600,
                      ),
                      maxLines: 2,
                      overflow: TextOverflow.ellipsis,
                    ),
                    if (displayName != null) ...[
                      const SizedBox(height: 2),
                      Text(
                        username,
                        style: TextStyle(
                          fontSize: 13,
                          color: theme.colorScheme.onSurfaceVariant,
                        ),
                        maxLines: 1,
                        overflow: TextOverflow.ellipsis,
                      ),
                    ],
                  ],
                ),
              ),
              const SizedBox(width: 8),
              TextButton.icon(
                icon: const Icon(Icons.logout_outlined, size: 18),
                label: const Text('Abmelden'),
                onPressed: () => _showLogoutDialog(context),
              ),
            ],
          ),
        ),
        // Nur für Login-Flow-Konten (2FA) sichtbar — Passwort-Konten heilen
        // sich still über das App-Passwort-Minting und sollen von dem ganzen
        // Flow-Mechanismus nichts mitbekommen.
        if (!AccountData().isDemo && AccountData().usesLoginFlow)
          AsyncListTile(
            leading: const Icon(Icons.cloud_sync_outlined),
            title: const Text('Nextcloud neu verbinden'),
            subtitle: const Text(
              'Bei Anmeldeproblemen in Talk oder Dateien',
            ),
            closeOnSuccess: false,
            onPressed: _reconnectNextcloud,
          ),
      ],
    );
  }

  /// Erneuert die Nextcloud-Zugangsdaten über den Login Flow v2 (inkl. des
  /// zweiten Talk-Durchlaufs) und bindet die Push-Subscription neu.
  Future<void> _reconnectNextcloud() async {
    final ok = await AppRoutes.openNextcloudLoginFlow(context);
    if (!ok || !mounted) return;
    // Neues App-Passwort = neue NC-Session: die Push-Subscription neu binden.
    unawaited(PushRegistration().register());
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('Nextcloud-Verbindung erneuert.')),
    );
  }

  Future<void> _showLogoutDialog(BuildContext context) async {
    // Flip AccountBloc state only after the dialog fully closes: doing it from
    // inside removeData (the previous approach) raced AsyncDialogAction's
    // pop(true) against the listener's popUntil(isFirst) and could leave the
    // navigator in an inconsistent state.
    final confirmed = await showDialog<bool>(
      context: context,
      builder: (dialogContext) => ConfirmDialog(
        title: 'Abmelden?',
        content: 'Möchtest du dich wirklich abmelden?',
        confirmButton: 'Abmelden',
        onConfirmAsync: _performLogout,
      ),
    );
    if (confirmed != true || !context.mounted) return;
    context.read<AccountBloc>().setStatus(AccountStatus.loggedOut);
  }

  // Ordered teardown: unregister push at Nextcloud + proxy and revoke the app
  // password (while Nextcloud credentials are still available), THEN revoke the
  // MC bearer token, and finally wipe local credentials. Each step is
  // best-effort so an offline logout still reaches a clean local state.
  Future<void> _performLogout() async {
    await PushRegistration().logoutCleanup();
    await AuthLogout().run();
    await AccountData().removeData();
    _cachedDisplayName = null;
  }
}

class _AvatarEditBadge extends StatelessWidget {
  final bool busy;
  final VoidCallback? onTap;
  const _AvatarEditBadge({required this.busy, required this.onTap});

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return Material(
      color: theme.colorScheme.primary,
      shape: const CircleBorder(),
      elevation: 2,
      child: InkWell(
        customBorder: const CircleBorder(),
        onTap: onTap,
        child: SizedBox(
          width: 27,
          height: 27,
          child: busy
              ? Padding(
                  padding: const EdgeInsets.all(6),
                  child: AppProgressIndicator.small(
                    color: theme.colorScheme.onPrimary,
                  ),
                )
              : Icon(
                  Icons.edit,
                  size: 14,
                  color: theme.colorScheme.onPrimary,
                ),
        ),
      ),
    );
  }
}
