import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:logging/logging.dart';
import 'package:userfront/i18n.dart';
import '../../../../core/i18n/locale_utils.dart';
import '../../../../core/services/auth_proxy_service.dart';
import '../../../../core/services/logout_service.dart';
import '../../../../core/ui/layout_breakpoints.dart';
import '../../../../core/ui/toast_service.dart';
import '../../../../core/widgets/language_selector.dart';
import '../../../../core/widgets/theme_toggle_button.dart';
import '../../data/models/user_profile_model.dart';
import '../../domain/notifiers/profile_notifier.dart';

class ProfilePage extends ConsumerStatefulWidget {
  const ProfilePage({super.key});

  @override
  ConsumerState<ProfilePage> createState() => _ProfilePageState();
}

class _ProfilePageState extends ConsumerState<ProfilePage> {
  static final _log = Logger('ProfilePage');

  UserProfile? _cachedProfile;
  String? _editingField;
  TextEditingController? _nameController;
  TextEditingController? _phoneController;
  TextEditingController? _departmentController;
  TextEditingController? _codeController;
  TextEditingController? _currentPasswordController;
  TextEditingController? _newPasswordController;
  TextEditingController? _confirmPasswordController;
  final FocusNode _nameFocus = FocusNode();
  final FocusNode _departmentFocus = FocusNode();
  final FocusNode _phoneFocus = FocusNode();
  final FocusNode _phoneCodeFocus = FocusNode();
  bool _isSavingField = false;
  String? _fieldSaveError;

  String _initialPhone = '';
  bool _isPhoneChanged = false;
  bool _isPhoneVerified = false;
  bool _isCodeSent = false;
  bool _isVerifying = false;

  bool _isPasswordSaving = false;
  String? _passwordError;
  String? _passwordSuccess;
  bool _showCurrentPassword = false;
  bool _showNewPassword = false;
  bool _showConfirmPassword = false;
  bool _isDesktopSideMenuOpen = true;
  Map<String, dynamic>? _passwordPolicy;
  bool _isPasswordPolicyLoading = false;

  Color get _ink => Theme.of(context).colorScheme.onSurface;
  Color get _surface => Theme.of(context).colorScheme.surface;
  Color get _border => Theme.of(context).colorScheme.outlineVariant;
  Color get _subtle => Theme.of(context).colorScheme.surfaceContainerLowest;

  String _renderTranslatedText(
    String key, {
    String? fallback,
    Map<String, String> values = const {},
  }) {
    var text = tr(key, fallback: fallback);
    values.forEach((name, value) {
      text = text.replaceAll('{{$name}}', value).replaceAll('{$name}', value);
    });
    return text;
  }

  @override
  void initState() {
    super.initState();
    _loadPasswordPolicy();
  }

  Future<void> _loadPasswordPolicy() async {
    setState(() {
      _isPasswordPolicyLoading = true;
    });
    try {
      final policy = await AuthProxyService.fetchPasswordPolicy();
      if (mounted) {
        setState(() {
          _passwordPolicy = policy;
        });
      }
    } catch (_) {
      // 정책 조회 실패 시 기본 검증 규칙 사용
    } finally {
      if (mounted) {
        setState(() {
          _isPasswordPolicyLoading = false;
        });
      }
    }
  }

  String _buildPasswordPolicyDescription() {
    if (_isPasswordPolicyLoading) {
      return tr('msg.userfront.signup.policy.loading');
    }

    final minLength = (_passwordPolicy?['minLength'] as int?) ?? 12;
    final minTypes = (_passwordPolicy?['minCharacterTypes'] as int?) ?? 0;
    final requiresLower = _passwordPolicy?['lowercase'] ?? true;
    final requiresUpper = _passwordPolicy?['uppercase'] ?? false;
    final requiresNumber = _passwordPolicy?['number'] ?? true;
    final requiresSymbol = _passwordPolicy?['nonAlphanumeric'] ?? true;

    final parts = <String>[
      _renderTranslatedText(
        'msg.userfront.signup.policy.min_length',
        values: {'count': '$minLength'},
      ),
    ];
    if (minTypes > 0) {
      parts.add(
        _renderTranslatedText(
          'msg.userfront.signup.policy.min_types',
          values: {'count': '$minTypes'},
        ),
      );
    }
    if (requiresLower) {
      parts.add(tr('msg.userfront.signup.policy.lowercase'));
    }
    if (requiresUpper) {
      parts.add(tr('msg.userfront.signup.policy.uppercase'));
    }
    if (requiresNumber) {
      parts.add(tr('msg.userfront.signup.policy.number'));
    }
    if (requiresSymbol) {
      parts.add(tr('msg.userfront.signup.policy.symbol'));
    }

    return _renderTranslatedText(
      'msg.userfront.signup.policy.summary',
      values: {'rules': parts.join(", ")},
    );
  }

  void _debugLog(
    String event, {
    String? field,
    String? reason,
    bool? changed,
    bool? hasFocus,
  }) {
    final parts = <String>['event=$event'];
    if (field != null) parts.add('field=$field');
    if (reason != null) parts.add('reason=$reason');
    if (changed != null) parts.add('changed=$changed');
    if (hasFocus != null) parts.add('hasFocus=$hasFocus');
    if (_editingField != null) parts.add('editing=$_editingField');
    _log.fine(parts.join(' '));
  }

  @override
  void dispose() {
    _nameController?.dispose();
    _phoneController?.dispose();
    _departmentController?.dispose();
    _codeController?.dispose();
    _currentPasswordController?.dispose();
    _newPasswordController?.dispose();
    _confirmPasswordController?.dispose();
    _nameFocus.dispose();
    _departmentFocus.dispose();
    _phoneFocus.dispose();
    _phoneCodeFocus.dispose();
    super.dispose();
  }

  Future<void> _logout() async {
    await LogoutService().logout();
  }

  void _ensureControllers(UserProfile profile) {
    _nameController ??= TextEditingController(text: profile.name);
    _departmentController ??= TextEditingController(text: profile.department);
    _codeController ??= TextEditingController();
    _currentPasswordController ??= TextEditingController();
    _newPasswordController ??= TextEditingController();
    _confirmPasswordController ??= TextEditingController();

    if (_phoneController == null) {
      _phoneController = TextEditingController(text: profile.phone);
      _initialPhone = profile.phone;
      _phoneController!.addListener(_onPhoneChanged);
    }

    if (_editingField != 'name' && _nameController!.text != profile.name) {
      _nameController!.text = profile.name;
    }
    if (_editingField != 'department' &&
        _departmentController!.text != profile.department) {
      _departmentController!.text = profile.department;
    }
    if (_editingField != 'phone' && _phoneController!.text != profile.phone) {
      _phoneController!.text = profile.phone;
      _initialPhone = profile.phone;
      _resetPhoneState();
    }
  }

  void _onPhoneChanged() {
    if (_phoneController == null) return;
    final changed = _phoneController!.text != _initialPhone;
    if (changed != _isPhoneChanged) {
      setState(() {
        _isPhoneChanged = changed;
        if (_isPhoneChanged) {
          _isPhoneVerified = false;
          _isCodeSent = false;
          _codeController?.clear();
        }
      });
    }
  }

  void _resetPhoneState() {
    _isPhoneChanged = false;
    _isPhoneVerified = false;
    _isCodeSent = false;
    _isVerifying = false;
    _codeController?.clear();
  }

  void _startEditing(String field, UserProfile profile) {
    _debugLog('start_editing', field: field);
    setState(() {
      _editingField = field;
      _fieldSaveError = null;
      if (field == 'name') {
        _nameController?.text = profile.name;
      } else if (field == 'department') {
        _departmentController?.text = profile.department;
      } else if (field == 'phone') {
        _phoneController?.text = profile.phone;
        _initialPhone = profile.phone;
        _resetPhoneState();
      }
    });
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (!mounted) return;
      if (field == 'name') {
        FocusScope.of(context).requestFocus(_nameFocus);
      } else if (field == 'department') {
        FocusScope.of(context).requestFocus(_departmentFocus);
      } else if (field == 'phone') {
        FocusScope.of(context).requestFocus(_phoneFocus);
      }
    });
  }

  void _cancelEditing(UserProfile profile) {
    setState(() {
      if (_editingField == 'name') {
        _nameController?.text = profile.name;
      } else if (_editingField == 'department') {
        _departmentController?.text = profile.department;
      } else if (_editingField == 'phone') {
        _phoneController?.text = profile.phone;
        _initialPhone = profile.phone;
        _resetPhoneState();
      }
      _editingField = null;
      _fieldSaveError = null;
    });
  }

  Future<void> _sendCode() async {
    final phone = _phoneController?.text ?? '';
    if (phone.isEmpty) return;

    setState(() => _isVerifying = true);
    try {
      await ref.read(profileRepositoryProvider).sendUpdateCode(phone);
      setState(() {
        _isCodeSent = true;
        _isVerifying = false;
      });
      if (mounted) {
        ToastService.info(tr('msg.userfront.profile.phone.code_sent'));
      }
    } catch (e) {
      setState(() => _isVerifying = false);
      if (mounted) {
        ToastService.error(
          tr(
            'msg.userfront.profile.phone.send_failed',
            params: {'error': e.toString()},
          ),
        );
      }
    }
  }

  Future<void> _verifyCode(UserProfile profile) async {
    final phone = _phoneController?.text ?? '';
    final code = _codeController?.text ?? '';
    if (code.isEmpty) return;

    setState(() => _isVerifying = true);
    try {
      await ref.read(profileRepositoryProvider).verifyUpdateCode(phone, code);
      setState(() {
        _isPhoneVerified = true;
        _isVerifying = false;
      });
      if (mounted) {
        ToastService.success(tr('msg.userfront.profile.phone.verified'));
      }
    } catch (e) {
      setState(() => _isVerifying = false);
      if (mounted) {
        ToastService.error(
          tr(
            'msg.userfront.profile.phone.verify_failed',
            params: {'error': e.toString()},
          ),
        );
      }
    }
  }

  Future<void> _changePassword() async {
    if (_isPasswordSaving) return;
    final currentPassword = _currentPasswordController?.text.trim() ?? '';
    final newPassword = _newPasswordController?.text.trim() ?? '';
    final confirmPassword = _confirmPasswordController?.text.trim() ?? '';

    if (currentPassword.isEmpty) {
      setState(
        () => _passwordError = tr(
          'msg.userfront.profile.password.current_required',
        ),
      );
      return;
    }
    if (newPassword.isEmpty) {
      setState(
        () =>
            _passwordError = tr('msg.userfront.profile.password.new_required'),
      );
      return;
    }

    final minLength = (_passwordPolicy?['minLength'] as int?) ?? 12;
    final minTypes = (_passwordPolicy?['minCharacterTypes'] as int?) ?? 0;
    final hasLower = RegExp(r'[a-z]').hasMatch(newPassword);
    final hasUpper = RegExp(r'[A-Z]').hasMatch(newPassword);
    final hasNumber = RegExp(r'[0-9]').hasMatch(newPassword);
    final hasSymbol = RegExp(r'[\W_]').hasMatch(newPassword);
    int typeCount = 0;
    if (hasLower) typeCount++;
    if (hasUpper) typeCount++;
    if (hasNumber) typeCount++;
    if (hasSymbol) typeCount++;

    if (newPassword.length < minLength) {
      setState(
        () => _passwordError = tr(
          'msg.userfront.reset.error.min_length',
          params: {'count': '$minLength'},
        ),
      );
      return;
    }
    if (minTypes > 0 && typeCount < minTypes) {
      setState(
        () => _passwordError = tr(
          'msg.userfront.reset.error.min_types',
          params: {'count': '$minTypes'},
        ),
      );
      return;
    }
    if ((_passwordPolicy?['lowercase'] ?? true) && !hasLower) {
      setState(
        () => _passwordError = tr('msg.userfront.reset.error.lowercase'),
      );
      return;
    }
    if ((_passwordPolicy?['uppercase'] ?? false) && !hasUpper) {
      setState(
        () => _passwordError = tr('msg.userfront.reset.error.uppercase'),
      );
      return;
    }
    if ((_passwordPolicy?['number'] ?? true) && !hasNumber) {
      setState(() => _passwordError = tr('msg.userfront.reset.error.number'));
      return;
    }
    if ((_passwordPolicy?['nonAlphanumeric'] ?? true) && !hasSymbol) {
      setState(() => _passwordError = tr('msg.userfront.reset.error.symbol'));
      return;
    }

    if (newPassword != confirmPassword) {
      setState(
        () => _passwordError = tr('msg.userfront.profile.password.mismatch'),
      );
      return;
    }

    setState(() {
      _passwordError = null;
      _passwordSuccess = null;
      _isPasswordSaving = true;
    });

    try {
      await ref
          .read(profileRepositoryProvider)
          .changePassword(
            currentPassword: currentPassword,
            newPassword: newPassword,
          );
      _currentPasswordController?.clear();
      _newPasswordController?.clear();
      _confirmPasswordController?.clear();
      setState(() {
        _passwordSuccess = null;
      });
      ToastService.success(tr('msg.userfront.profile.password.changed'));
    } catch (e) {
      final message = e.toString().replaceFirst('Exception: ', '');
      setState(() {
        _passwordError = tr(
          'msg.userfront.profile.password.change_failed',
          params: {'error': message},
        );
      });
      ToastService.error(
        tr(
          'msg.userfront.profile.password.change_failed',
          params: {'error': message},
        ),
      );
    } finally {
      if (mounted) {
        setState(() => _isPasswordSaving = false);
      }
    }
  }

  bool _hasFieldChanged(UserProfile profile, String field) {
    if (field == 'name') {
      return (_nameController?.text.trim() ?? '') != profile.name;
    }
    if (field == 'department') {
      return (_departmentController?.text.trim() ?? '') != profile.department;
    }
    if (field == 'phone') {
      return (_phoneController?.text.trim() ?? '') != profile.phone;
    }
    return false;
  }

  Future<void> _saveField(UserProfile profile) async {
    if (_editingField == null) return;
    if (_isSavingField) {
      _debugLog('save_skip', reason: 'saving_in_flight');
      return;
    }

    setState(() {
      _fieldSaveError = null;
    });

    final currentField = _editingField!;

    final nextName = currentField == 'name'
        ? _nameController!.text.trim()
        : profile.name;
    final nextPhone = currentField == 'phone'
        ? _phoneController!.text.trim()
        : profile.phone;
    final nextDepartment = currentField == 'department'
        ? _departmentController!.text.trim()
        : profile.department;

    _debugLog('save_attempt', field: currentField);

    if (currentField == 'name' && nextName.isEmpty) {
      _debugLog('save_skip', field: currentField, reason: 'empty_name');
      setState(() {
        _fieldSaveError = tr('msg.userfront.profile.name_required');
      });
      return;
    }
    if (currentField == 'department' && nextDepartment.isEmpty) {
      _debugLog('save_skip', field: currentField, reason: 'empty_department');
      setState(() {
        _fieldSaveError = tr('msg.userfront.profile.department_required');
      });
      return;
    }
    if (currentField == 'phone') {
      if (nextPhone.isEmpty) {
        _debugLog('save_skip', field: currentField, reason: 'empty_phone');
        setState(() {
          _fieldSaveError = tr('msg.userfront.profile.phone_required');
        });
        return;
      }
      if (_isPhoneChanged && !_isPhoneVerified) {
        _debugLog(
          'save_skip',
          field: currentField,
          reason: 'phone_not_verified',
        );
        setState(() {
          _fieldSaveError = tr('msg.userfront.profile.phone_verify_required');
        });
        return;
      }
    }

    if (!_hasFieldChanged(profile, currentField)) {
      _debugLog(
        'save_skip',
        field: currentField,
        reason: 'unchanged',
        changed: false,
      );
      setState(() {
        if (_editingField == 'phone') {
          _resetPhoneState();
        }
        _editingField = null;
      });
      return;
    }

    setState(() {
      _isSavingField = true;
    });

    _debugLog('save_dispatch', field: currentField, changed: true);

    try {
      await ref
          .read(profileProvider.notifier)
          .updateProfile(
            name: nextName,
            phone: nextPhone,
            department: nextDepartment,
          );
      if (mounted) {
        setState(() {
          if (currentField == 'phone') {
            _initialPhone = nextPhone;
            _resetPhoneState();
          }
          _editingField = null;
        });
        _debugLog('save_success', field: currentField);
        ToastService.success(tr('msg.userfront.profile.update_success'));
      }
    } catch (e) {
      _debugLog('save_failed', field: currentField, reason: e.toString());
      if (mounted) {
        setState(() {
          _fieldSaveError = tr(
            'msg.userfront.profile.update_failed',
            params: {'error': e.toString().replaceFirst('Exception: ', '')},
          );
        });
      }
    } finally {
      if (mounted) {
        setState(() {
          _isSavingField = false;
        });
      }
    }
  }

  Widget _buildSideMenu(BuildContext context) {
    return Column(
      children: [
        Expanded(
          child: ListView(
            padding: const EdgeInsets.symmetric(vertical: 12),
            children: [
              ListTile(
                leading: const Icon(Icons.home_outlined),
                title: Text(tr('ui.userfront.nav.dashboard')),
                onTap: () => context.go(buildLocalizedHomePath(Uri.base)),
              ),
              ListTile(
                leading: const Icon(Icons.person_outline),
                title: Text(tr('ui.userfront.nav.profile')),
                selected: true,
                onTap: () => context.go('/profile'),
              ),
              ListTile(
                leading: const Icon(Icons.qr_code_scanner),
                title: Text(tr('ui.userfront.nav.qr_scan')),
                onTap: () => context.go('/scan'),
              ),
              const Divider(),
              ListTile(
                leading: const Icon(Icons.logout),
                title: Text(tr('ui.userfront.nav.logout')),
                onTap: _logout,
              ),
            ],
          ),
        ),
        const Padding(
          padding: EdgeInsets.only(bottom: 16),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              ThemeToggleButton(),
              SizedBox(height: 8),
              LanguageSelector(compact: true),
            ],
          ),
        ),
      ],
    );
  }

  Widget _buildSectionTitle(String title, String subtitle) {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.end,
      children: [
        Text(
          title,
          style: TextStyle(
            fontSize: 18,
            fontWeight: FontWeight.w700,
            color: _ink,
          ),
        ),
        const SizedBox(width: 12),
        Text(subtitle, style: TextStyle(fontSize: 13, color: Colors.grey[600])),
      ],
    );
  }

  Widget _buildInfoChip(IconData icon, String label) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
      decoration: BoxDecoration(
        color: _subtle,
        borderRadius: BorderRadius.circular(999),
        border: Border.all(color: _border),
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(icon, size: 16, color: _ink),
          const SizedBox(width: 6),
          Text(
            label,
            style: TextStyle(
              fontSize: 12,
              color: _ink,
              fontWeight: FontWeight.w600,
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildHeaderCard(UserProfile profile) {
    final name = profile.name.isEmpty
        ? tr('msg.userfront.profile.name_missing')
        : profile.name;
    final email = profile.email.isEmpty
        ? tr('msg.userfront.profile.email_missing')
        : profile.email;
    final department = profile.department.isEmpty
        ? tr('msg.userfront.profile.department_missing')
        : profile.department;

    return Container(
      width: double.infinity,
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        color: _surface,
        borderRadius: BorderRadius.circular(16),
        border: Border.all(color: _border),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withValues(alpha: 10),
            blurRadius: 18,
            offset: const Offset(0, 8),
          ),
        ],
      ),
      child: Row(
        children: [
          const CircleAvatar(radius: 32, child: Icon(Icons.person, size: 32)),
          const SizedBox(width: 16),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  _renderTranslatedText(
                    'msg.userfront.profile.greeting',
                    fallback: 'Hello, {{name}}.',
                    values: {'name': name},
                  ),
                  style: TextStyle(
                    fontSize: 20,
                    fontWeight: FontWeight.w700,
                    color: _ink,
                  ),
                ),
                const SizedBox(height: 6),
                Text(
                  email,
                  style: TextStyle(color: Colors.grey[600], fontSize: 14),
                ),
                const SizedBox(height: 12),
                Wrap(
                  spacing: 8,
                  runSpacing: 8,
                  children: [
                    _buildInfoChip(
                      Icons.badge_outlined,
                      tr('ui.userfront.profile.manage'),
                    ),
                    _buildInfoChip(
                      Icons.apartment,
                      profile.tenant?.name ?? department,
                    ),
                  ],
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildCard(Widget child) {
    return Container(
      width: double.infinity,
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: _surface,
        borderRadius: BorderRadius.circular(16),
        border: Border.all(color: _border),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withValues(alpha: 8),
            blurRadius: 12,
            offset: const Offset(0, 6),
          ),
        ],
      ),
      child: child,
    );
  }

  Widget _buildReadOnlyTile(String label, String value) {
    final displayValue = value.isEmpty ? '-' : value;
    return ListTile(
      contentPadding: EdgeInsets.zero,
      title: Text(label),
      subtitle: Text(displayValue),
      trailing: Text(
        tr('ui.common.read_only'),
        style: TextStyle(color: Colors.grey[500], fontSize: 12),
      ),
    );
  }

  Widget _buildEditableTile({
    required String field,
    required String label,
    required String value,
    required UserProfile profile,
    required bool isUpdating,
    required TextEditingController controller,
  }) {
    final isEditing = _editingField == field;
    final displayValue = value.isEmpty ? '-' : value;
    final isCompact = MediaQuery.of(context).size.width < 640;

    if (!isEditing) {
      return ListTile(
        contentPadding: EdgeInsets.zero,
        title: Text(label),
        subtitle: Text(displayValue),
        trailing: TextButton(
          key: Key('profile-$field-edit-button'),
          onPressed: isUpdating ? null : () => _startEditing(field, profile),
          child: Text(tr('ui.common.edit')),
        ),
      );
    }

    final hasChanged = _hasFieldChanged(profile, field);

    final inputField = TextField(
      key: Key('profile-$field-input'),
      controller: controller,
      focusNode: field == 'name' ? _nameFocus : _departmentFocus,
      textInputAction: TextInputAction.done,
      onSubmitted: (_) => _saveField(profile),
      onChanged: (_) {
        setState(() {
          _fieldSaveError = null;
        });
      },
      decoration: InputDecoration(
        border: const OutlineInputBorder(),
        hintText: label,
        errorText: _fieldSaveError,
      ),
    );
    final saveButton = ElevatedButton(
      key: Key('profile-$field-save-button'),
      onPressed: isUpdating || !hasChanged || _isSavingField
          ? null
          : () => _saveField(profile),
      child: _isSavingField
          ? const SizedBox(
              width: 16,
              height: 16,
              child: CircularProgressIndicator(strokeWidth: 2),
            )
          : Text(tr('ui.common.save')),
    );
    final cancelButton = OutlinedButton(
      key: Key('profile-$field-cancel-button'),
      onPressed: isUpdating || _isSavingField
          ? null
          : () => _cancelEditing(profile),
      child: Text(tr('ui.common.cancel')),
    );

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(label, style: const TextStyle(fontWeight: FontWeight.w600)),
        const SizedBox(height: 8),
        if (isCompact) ...[
          inputField,
          const SizedBox(height: 12),
          Wrap(spacing: 8, runSpacing: 8, children: [saveButton, cancelButton]),
        ] else
          Row(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Expanded(child: inputField),
              const SizedBox(width: 12),
              saveButton,
              const SizedBox(width: 8),
              cancelButton,
            ],
          ),
      ],
    );
  }

  Widget _buildPhoneEditor(UserProfile profile, bool isUpdating) {
    final isEditing = _editingField == 'phone';
    final displayValue = profile.phone.isEmpty ? '-' : profile.phone;

    if (!isEditing) {
      return ListTile(
        contentPadding: EdgeInsets.zero,
        title: Text(tr('ui.userfront.profile.phone.title')),
        subtitle: Text(displayValue),
        trailing: TextButton(
          onPressed: isUpdating ? null : () => _startEditing('phone', profile),
          child: Text(tr('ui.common.edit')),
        ),
      );
    }

    final hasChanged = _hasFieldChanged(profile, 'phone');
    final canSave = hasChanged && (!_isPhoneChanged || _isPhoneVerified);

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          tr('ui.userfront.profile.phone.title'),
          style: const TextStyle(fontWeight: FontWeight.w600),
        ),
        const SizedBox(height: 8),
        Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Expanded(
              child: TextField(
                controller: _phoneController,
                focusNode: _phoneFocus,
                keyboardType: TextInputType.phone,
                textInputAction: TextInputAction.done,
                onSubmitted: (_) => _saveField(profile),
                onChanged: (_) {
                  setState(() {
                    _fieldSaveError = null;
                  });
                },
                decoration: InputDecoration(
                  border: const OutlineInputBorder(),
                  hintText: '01012345678',
                  errorText: _fieldSaveError,
                  suffixIcon: _isPhoneVerified
                      ? const Icon(Icons.check_circle, color: Colors.green)
                      : null,
                ),
                enabled: !_isPhoneVerified,
              ),
            ),
            const SizedBox(width: 8),
            if (_isPhoneChanged && !_isPhoneVerified)
              ElevatedButton(
                onPressed: _isVerifying ? null : _sendCode,
                child: Text(
                  _isCodeSent
                      ? tr('ui.common.resend')
                      : tr('ui.userfront.profile.phone.request_code'),
                ),
              ),
            const SizedBox(width: 8),
            ElevatedButton(
              onPressed: isUpdating || !canSave || _isSavingField
                  ? null
                  : () => _saveField(profile),
              child: _isSavingField
                  ? const SizedBox(
                      width: 16,
                      height: 16,
                      child: CircularProgressIndicator(strokeWidth: 2),
                    )
                  : Text(tr('ui.common.save')),
            ),
            const SizedBox(width: 8),
            OutlinedButton(
              onPressed: isUpdating || _isSavingField
                  ? null
                  : () => _cancelEditing(profile),
              child: Text(tr('ui.common.cancel')),
            ),
          ],
        ),
        if (_isCodeSent && !_isPhoneVerified) ...[
          const SizedBox(height: 12),
          Row(
            crossAxisAlignment: CrossAxisAlignment.end,
            children: [
              Expanded(
                child: TextField(
                  controller: _codeController,
                  focusNode: _phoneCodeFocus,
                  keyboardType: TextInputType.number,
                  textInputAction: TextInputAction.done,
                  onSubmitted: (_) => _verifyCode(profile),
                  decoration: InputDecoration(
                    border: const OutlineInputBorder(),
                    hintText: tr('ui.userfront.profile.phone.code_hint'),
                  ),
                ),
              ),
              const SizedBox(width: 8),
              ElevatedButton(
                onPressed: _isVerifying ? null : () => _verifyCode(profile),
                child: Text(tr('ui.common.confirm')),
              ),
            ],
          ),
        ],
        if (_isPhoneChanged && !_isPhoneVerified)
          Padding(
            padding: const EdgeInsets.only(top: 8.0),
            child: Text(
              tr('msg.userfront.profile.phone.verify_notice'),
              style: const TextStyle(color: Colors.orange, fontSize: 12),
            ),
          ),
      ],
    );
  }

  Widget _buildPasswordSection() {
    return _buildCard(
      Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            tr('ui.userfront.profile.password.title'),
            style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w700),
          ),
          const SizedBox(height: 8),
          Text(
            tr('msg.userfront.profile.password.subtitle'),
            style: TextStyle(
              color: Theme.of(context).colorScheme.onSurfaceVariant,
            ),
          ),
          const SizedBox(height: 8),
          Text(
            _buildPasswordPolicyDescription(),
            style: TextStyle(
              color: Theme.of(context).colorScheme.onSurfaceVariant,
              fontSize: 12,
            ),
          ),
          const SizedBox(height: 16),
          TextField(
            controller: _currentPasswordController,
            obscureText: !_showCurrentPassword,
            decoration: InputDecoration(
              labelText: tr('ui.userfront.profile.password.current'),
              border: const OutlineInputBorder(),
              suffixIcon: IconButton(
                icon: Icon(
                  _showCurrentPassword
                      ? Icons.visibility_off
                      : Icons.visibility,
                ),
                onPressed: () => setState(() {
                  _showCurrentPassword = !_showCurrentPassword;
                }),
              ),
            ),
          ),
          const SizedBox(height: 12),
          TextField(
            controller: _newPasswordController,
            obscureText: !_showNewPassword,
            decoration: InputDecoration(
              labelText: tr('ui.userfront.profile.password.new'),
              border: const OutlineInputBorder(),
              suffixIcon: IconButton(
                icon: Icon(
                  _showNewPassword ? Icons.visibility_off : Icons.visibility,
                ),
                onPressed: () => setState(() {
                  _showNewPassword = !_showNewPassword;
                }),
              ),
            ),
          ),
          const SizedBox(height: 12),
          TextField(
            controller: _confirmPasswordController,
            obscureText: !_showConfirmPassword,
            decoration: InputDecoration(
              labelText: tr('ui.userfront.profile.password.confirm'),
              border: const OutlineInputBorder(),
              suffixIcon: IconButton(
                icon: Icon(
                  _showConfirmPassword
                      ? Icons.visibility_off
                      : Icons.visibility,
                ),
                onPressed: () => setState(() {
                  _showConfirmPassword = !_showConfirmPassword;
                }),
              ),
            ),
          ),
          if (_passwordError != null) ...[
            const SizedBox(height: 12),
            Text(_passwordError!, style: const TextStyle(color: Colors.red)),
          ],
          if (_passwordSuccess != null) ...[
            const SizedBox(height: 12),
            Text(
              _passwordSuccess!,
              style: const TextStyle(color: Colors.green),
            ),
          ],
          const SizedBox(height: 16),
          Row(
            children: [
              ElevatedButton(
                onPressed: _isPasswordSaving ? null : _changePassword,
                child: _isPasswordSaving
                    ? const SizedBox(
                        width: 18,
                        height: 18,
                        child: CircularProgressIndicator(strokeWidth: 2),
                      )
                    : Text(tr('ui.userfront.profile.password.change')),
              ),
              const SizedBox(width: 12),
              TextButton(
                onPressed: () => context.go('/recovery'),
                child: Text(tr('ui.userfront.profile.password.forgot')),
              ),
            ],
          ),
        ],
      ),
    );
  }

  Widget _buildContent(UserProfile profile, bool isUpdating) {
    return RefreshIndicator(
      onRefresh: () => ref.read(profileProvider.notifier).loadProfile(),
      child: LayoutBuilder(
        builder: (context, constraints) {
          return Align(
            alignment: Alignment.topCenter,
            child: ConstrainedBox(
              constraints: const BoxConstraints(maxWidth: 1200),
              child: ListView(
                padding: const EdgeInsets.all(24.0),
                children: [
                  _buildHeaderCard(profile),
                  const SizedBox(height: 28),
                  _buildSectionTitle(
                    tr('ui.userfront.profile.section.basic'),
                    tr('msg.userfront.profile.section.basic'),
                  ),
                  const SizedBox(height: 12),
                  _buildCard(
                    Column(
                      children: [
                        _buildEditableTile(
                          field: 'name',
                          label: tr('ui.userfront.profile.field.name'),
                          value: profile.name,
                          profile: profile,
                          isUpdating: isUpdating,
                          controller: _nameController!,
                        ),
                        const Divider(height: 24),
                        _buildReadOnlyTile(
                          tr('ui.userfront.profile.field.email'),
                          profile.email,
                        ),
                        const Divider(height: 24),
                        _buildPhoneEditor(profile, isUpdating),
                      ],
                    ),
                  ),
                  const SizedBox(height: 28),
                  _buildSectionTitle(
                    tr('ui.userfront.profile.section.organization'),
                    tr('msg.userfront.profile.section.organization'),
                  ),
                  const SizedBox(height: 12),
                  _buildCard(
                    Column(
                      children: [
                        _buildEditableTile(
                          field: 'department',
                          label: tr('ui.userfront.profile.field.department'),
                          value: profile.department,
                          profile: profile,
                          isUpdating: isUpdating,
                          controller: _departmentController!,
                        ),
                        const Divider(height: 24),
                        _buildReadOnlyTile(
                          tr('ui.userfront.profile.field.affiliation'),
                          profile.affiliationType,
                        ),
                        if (profile.tenant != null) ...[
                          const Divider(height: 24),
                          _buildReadOnlyTile(
                            tr('ui.userfront.profile.field.tenant'),
                            profile.tenant!.name,
                          ),
                        ],
                        if (profile.tenant?.slug.isNotEmpty ?? false) ...[
                          const Divider(height: 24),
                          _buildReadOnlyTile(
                            tr('ui.userfront.profile.field.tenant_slug'),
                            profile.tenant!.slug,
                          ),
                        ],
                      ],
                    ),
                  ),
                  const SizedBox(height: 28),
                  _buildSectionTitle(
                    tr('ui.userfront.profile.section.security'),
                    tr('msg.userfront.profile.section.security'),
                  ),
                  const SizedBox(height: 12),
                  _buildPasswordSection(),
                  if (isUpdating || _isVerifying) ...[
                    const SizedBox(height: 24),
                    const Center(child: CircularProgressIndicator()),
                  ],
                ],
              ),
            ),
          );
        },
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    final profileState = ref.watch(profileProvider);
    if (profileState.value != null) {
      _cachedProfile = profileState.value;
    }

    final profile = profileState.value ?? _cachedProfile;
    if (profile == null) {
      return Scaffold(
        appBar: AppBar(title: Text(tr('ui.userfront.nav.profile'))),
        body: profileState.isLoading
            ? const Center(child: CircularProgressIndicator())
            : Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Text(tr('msg.userfront.profile.load_failed')),
                    const SizedBox(height: 16),
                    ElevatedButton(
                      onPressed: () =>
                          ref.read(profileProvider.notifier).loadProfile(),
                      child: Text(tr('ui.common.retry')),
                    ),
                  ],
                ),
              ),
      );
    }

    _ensureControllers(profile);

    final isWide = MediaQuery.of(context).size.width >= sideMenuBreakpoint;
    final isUpdating = profileState.isLoading;

    return Scaffold(
      backgroundColor: _subtle,
      appBar: AppBar(
        leading: isWide
            ? IconButton(
                icon: Icon(
                  _isDesktopSideMenuOpen ? Icons.menu_open : Icons.menu,
                ),
                tooltip: _isDesktopSideMenuOpen
                    ? tr('ui.common.collapse')
                    : '펼치기',
                onPressed: () {
                  setState(() {
                    _isDesktopSideMenuOpen = !_isDesktopSideMenuOpen;
                  });
                },
              )
            : Builder(
                builder: (context) => IconButton(
                  icon: const Icon(Icons.menu),
                  tooltip: MaterialLocalizations.of(
                    context,
                  ).openAppDrawerTooltip,
                  onPressed: () => Scaffold.of(context).openDrawer(),
                ),
              ),
        title: Text(
          tr('ui.userfront.app_title'),
          style: const TextStyle(fontWeight: FontWeight.bold),
        ),
        actions: [
          const ThemeToggleButton(compact: true),
          IconButton(
            icon: const Icon(Icons.home_outlined),
            tooltip: tr('ui.userfront.nav.dashboard'),
            onPressed: () => context.go(buildLocalizedHomePath(Uri.base)),
          ),
          IconButton(
            icon: const Icon(Icons.qr_code_scanner),
            tooltip: tr('ui.userfront.nav.qr_scan'),
            onPressed: () => context.push('/scan'),
          ),
          IconButton(
            icon: const Icon(Icons.logout),
            tooltip: tr('ui.userfront.nav.logout'),
            onPressed: _logout,
          ),
        ],
      ),
      drawer: isWide ? null : Drawer(child: _buildSideMenu(context)),
      body: Row(
        children: [
          if (isWide && _isDesktopSideMenuOpen)
            SizedBox(width: 240, child: _buildSideMenu(context)),
          Expanded(child: _buildContent(profile, isUpdating)),
        ],
      ),
    );
  }
}
