import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_lucide/flutter_lucide.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';

import '../api/endpoints/settings.dart';
import '../api/errors.dart';
import '../library/library_providers.dart' show dioProvider;
import '../models/my_profile.dart';
import '../shared/widgets/main_app_bar_actions.dart';
import '../theme/theme_extension.dart';
import 'about_section.dart';
import 'storage_section.dart';
import '../theme/theme_mode_provider.dart';

final _settingsApiProvider = FutureProvider<SettingsApi>((ref) async {
  return SettingsApi(await ref.watch(dioProvider.future));
});

final _profileProvider = FutureProvider<MyProfile>((ref) async {
  return (await ref.watch(_settingsApiProvider.future)).getProfile();
});

final _lbStatusProvider = FutureProvider<ListenBrainzStatus>((ref) async {
  return (await ref.watch(_settingsApiProvider.future)).getListenBrainz();
});

class SettingsScreen extends ConsumerWidget {
  const SettingsScreen({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final fs = Theme.of(context).extension<FabledSwordTheme>()!;
    return Scaffold(
      backgroundColor: fs.obsidian,
      appBar: AppBar(
        backgroundColor: fs.obsidian,
        elevation: 0,
        leading: IconButton(
          icon: Icon(LucideIcons.arrow_left, color: fs.parchment),
          onPressed: () => context.pop(),
        ),
        title: Text('Settings', style: TextStyle(color: fs.parchment)),
        actions: const [MainAppBarActions(currentRoute: '/settings')],
      ),
      body: ListView(
        padding: const EdgeInsets.symmetric(vertical: 8),
        children: const [
          _ProfileSection(),
          _Divider(),
          _RequestsSection(),
          _Divider(),
          _AppearanceSection(),
          _Divider(),
          StorageSection(),
          _Divider(),
          _PasswordSection(),
          _Divider(),
          _ListenBrainzSection(),
          _Divider(),
          AboutSection(),
          _AdminSection(),
          SizedBox(height: 96),
        ],
      ),
    );
  }
}

class _Divider extends StatelessWidget {
  const _Divider();
  @override
  Widget build(BuildContext context) {
    final fs = Theme.of(context).extension<FabledSwordTheme>()!;
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 16),
      child: Container(height: 1, color: fs.iron),
    );
  }
}

class _SectionHeader extends StatelessWidget {
  const _SectionHeader(this.label);
  final String label;
  @override
  Widget build(BuildContext context) {
    final fs = Theme.of(context).extension<FabledSwordTheme>()!;
    return Padding(
      padding: const EdgeInsets.fromLTRB(16, 4, 16, 8),
      child: Text(
        label,
        style: TextStyle(
          color: fs.parchment,
          fontSize: 16,
          fontWeight: FontWeight.w500,
        ),
      ),
    );
  }
}

class _RequestsSection extends StatelessWidget {
  const _RequestsSection();

  @override
  Widget build(BuildContext context) {
    final fs = Theme.of(context).extension<FabledSwordTheme>()!;
    return ListTile(
      key: const Key('settings_requests_card'),
      leading: Icon(LucideIcons.list_music, color: fs.parchment),
      title: Text(
        'My requests',
        style: TextStyle(
          color: fs.parchment,
          fontFamily: 'Fraunces',
          fontSize: 18,
        ),
      ),
      subtitle: Text(
        "Track what you've asked Minstrel to add",
        style: TextStyle(color: fs.ash),
      ),
      trailing: Icon(LucideIcons.chevron_right, color: fs.ash),
      onTap: () => context.push('/requests'),
    );
  }
}

/// Renders an "Admin" entry only when the current profile has
/// `is_admin = true`. Returns an empty SizedBox otherwise so the
/// const-children layout above stays valid.
class _AdminSection extends ConsumerWidget {
  const _AdminSection();

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final fs = Theme.of(context).extension<FabledSwordTheme>()!;
    final profile = ref.watch(_profileProvider).value;
    if (profile == null || !profile.isAdmin) return const SizedBox.shrink();
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        const _Divider(),
        ListTile(
          key: const Key('settings_admin_card'),
          leading: Icon(LucideIcons.shield, color: fs.parchment),
          title: Text(
            'Admin',
            style: TextStyle(
              color: fs.parchment,
              fontFamily: 'Fraunces',
              fontSize: 18,
            ),
          ),
          subtitle: Text(
            'Manage requests, quarantine, and users',
            style: TextStyle(color: fs.ash),
          ),
          trailing: Icon(LucideIcons.chevron_right, color: fs.ash),
          onTap: () => context.push('/admin'),
        ),
      ],
    );
  }
}

class _ProfileSection extends ConsumerStatefulWidget {
  const _ProfileSection();
  @override
  ConsumerState<_ProfileSection> createState() => _ProfileSectionState();
}

class _ProfileSectionState extends ConsumerState<_ProfileSection> {
  final _displayName = TextEditingController();
  final _email = TextEditingController();
  bool _initialized = false;
  bool _saving = false;

  @override
  void dispose() {
    _displayName.dispose();
    _email.dispose();
    super.dispose();
  }

  Future<void> _save() async {
    final fs = Theme.of(context).extension<FabledSwordTheme>()!;
    setState(() => _saving = true);
    try {
      final api = await ref.read(_settingsApiProvider.future);
      await api.updateProfile(
        displayName: _displayName.text.trim(),
        email: _email.text.trim(),
      );
      ref.invalidate(_profileProvider);
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: const Text('Profile saved.'),
            backgroundColor: fs.iron,
          ),
        );
      }
    } on DioException catch (e) {
      if (mounted) {
        final msg = ApiError.fromDio(e).code;
        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
          content: Text('Save failed: $msg'),
          backgroundColor: fs.error,
        ));
      }
    } finally {
      if (mounted) setState(() => _saving = false);
    }
  }

  @override
  Widget build(BuildContext context) {
    final fs = Theme.of(context).extension<FabledSwordTheme>()!;
    final profile = ref.watch(_profileProvider);
    return profile.when(
      loading: () => const Padding(
        padding: EdgeInsets.all(16),
        child: Center(child: CircularProgressIndicator()),
      ),
      error: (e, _) => Padding(
        padding: const EdgeInsets.all(16),
        child: Text('$e', style: TextStyle(color: fs.error)),
      ),
      data: (p) {
        if (!_initialized) {
          _displayName.text = p.displayName ?? '';
          _email.text = p.email ?? '';
          _initialized = true;
        }
        return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
          const _SectionHeader('Profile'),
          Padding(
            padding: const EdgeInsets.fromLTRB(16, 0, 16, 4),
            child: Text(
              'Signed in as ${p.username}${p.isAdmin ? " · admin" : ""}',
              style: TextStyle(color: fs.ash, fontSize: 12),
            ),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
            child: TextField(
              controller: _displayName,
              style: TextStyle(color: fs.parchment),
              decoration: _inputDecoration(fs, 'Display name'),
            ),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
            child: TextField(
              controller: _email,
              style: TextStyle(color: fs.parchment),
              keyboardType: TextInputType.emailAddress,
              decoration: _inputDecoration(fs, 'Email (for password reset)'),
            ),
          ),
          Padding(
            padding: const EdgeInsets.fromLTRB(16, 8, 16, 0),
            child: FilledButton(
              onPressed: _saving ? null : _save,
              style: FilledButton.styleFrom(
                backgroundColor: fs.accent,
                foregroundColor: fs.parchment,
              ),
              child: Text(_saving ? 'Saving…' : 'Save profile'),
            ),
          ),
        ]);
      },
    );
  }
}

class _PasswordSection extends ConsumerStatefulWidget {
  const _PasswordSection();
  @override
  ConsumerState<_PasswordSection> createState() => _PasswordSectionState();
}

class _PasswordSectionState extends ConsumerState<_PasswordSection> {
  final _current = TextEditingController();
  final _next = TextEditingController();
  final _confirm = TextEditingController();
  bool _saving = false;

  @override
  void dispose() {
    _current.dispose();
    _next.dispose();
    _confirm.dispose();
    super.dispose();
  }

  Future<void> _change() async {
    final fs = Theme.of(context).extension<FabledSwordTheme>()!;
    if (_next.text != _confirm.text) {
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(
        content: const Text('New passwords do not match.'),
        backgroundColor: fs.error,
      ));
      return;
    }
    if (_next.text.length < 8) {
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(
        content: const Text('Password must be at least 8 characters.'),
        backgroundColor: fs.error,
      ));
      return;
    }
    setState(() => _saving = true);
    try {
      final api = await ref.read(_settingsApiProvider.future);
      await api.changePassword(current: _current.text, next: _next.text);
      _current.clear();
      _next.clear();
      _confirm.clear();
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
          content: const Text('Password changed.'),
          backgroundColor: fs.iron,
        ));
      }
    } on DioException catch (e) {
      if (mounted) {
        final msg = ApiError.fromDio(e).code;
        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
          content: Text('Change failed: $msg'),
          backgroundColor: fs.error,
        ));
      }
    } finally {
      if (mounted) setState(() => _saving = false);
    }
  }

  @override
  Widget build(BuildContext context) {
    final fs = Theme.of(context).extension<FabledSwordTheme>()!;
    return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
      const _SectionHeader('Password'),
      Padding(
        padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
        child: TextField(
          controller: _current,
          obscureText: true,
          style: TextStyle(color: fs.parchment),
          decoration: _inputDecoration(fs, 'Current password'),
        ),
      ),
      Padding(
        padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
        child: TextField(
          controller: _next,
          obscureText: true,
          style: TextStyle(color: fs.parchment),
          decoration: _inputDecoration(fs, 'New password'),
        ),
      ),
      Padding(
        padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
        child: TextField(
          controller: _confirm,
          obscureText: true,
          style: TextStyle(color: fs.parchment),
          decoration: _inputDecoration(fs, 'Confirm new password'),
        ),
      ),
      Padding(
        padding: const EdgeInsets.fromLTRB(16, 8, 16, 0),
        child: FilledButton(
          onPressed: _saving ? null : _change,
          style: FilledButton.styleFrom(
            backgroundColor: fs.accent,
            foregroundColor: fs.parchment,
          ),
          child: Text(_saving ? 'Changing…' : 'Change password'),
        ),
      ),
    ]);
  }
}

class _ListenBrainzSection extends ConsumerStatefulWidget {
  const _ListenBrainzSection();
  @override
  ConsumerState<_ListenBrainzSection> createState() =>
      _ListenBrainzSectionState();
}

class _ListenBrainzSectionState extends ConsumerState<_ListenBrainzSection> {
  final _token = TextEditingController();
  bool _saving = false;

  @override
  void dispose() {
    _token.dispose();
    super.dispose();
  }

  Future<void> _saveToken() async {
    final fs = Theme.of(context).extension<FabledSwordTheme>()!;
    if (_token.text.trim().isEmpty) return;
    setState(() => _saving = true);
    try {
      final api = await ref.read(_settingsApiProvider.future);
      await api.setListenBrainzToken(_token.text.trim());
      _token.clear();
      ref.invalidate(_lbStatusProvider);
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
          content: const Text('Token saved.'),
          backgroundColor: fs.iron,
        ));
      }
    } on DioException catch (e) {
      if (mounted) {
        final msg = ApiError.fromDio(e).code;
        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
          content: Text('Save failed: $msg'),
          backgroundColor: fs.error,
        ));
      }
    } finally {
      if (mounted) setState(() => _saving = false);
    }
  }

  Future<void> _toggleEnabled(bool value) async {
    final fs = Theme.of(context).extension<FabledSwordTheme>()!;
    try {
      final api = await ref.read(_settingsApiProvider.future);
      await api.setListenBrainzEnabled(value);
      ref.invalidate(_lbStatusProvider);
    } on DioException catch (e) {
      if (mounted) {
        final msg = ApiError.fromDio(e).code;
        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
          content: Text('Toggle failed: $msg'),
          backgroundColor: fs.error,
        ));
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    final fs = Theme.of(context).extension<FabledSwordTheme>()!;
    final status = ref.watch(_lbStatusProvider);
    return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
      const _SectionHeader('ListenBrainz'),
      Padding(
        padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
        child: Text(
          'Get a token at listenbrainz.org/profile. Tokens are stored '
          'unencrypted on this server — treat as sensitive.',
          style: TextStyle(color: fs.ash, fontSize: 12),
        ),
      ),
      status.when(
        loading: () => const Padding(
          padding: EdgeInsets.all(16),
          child: Center(child: CircularProgressIndicator()),
        ),
        error: (e, _) => Padding(
          padding: const EdgeInsets.all(16),
          child: Text('$e', style: TextStyle(color: fs.error)),
        ),
        data: (s) => Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
              child: TextField(
                controller: _token,
                obscureText: true,
                style: TextStyle(color: fs.parchment),
                decoration: _inputDecoration(
                  fs,
                  s.tokenSet ? 'Update token (current is set)' : 'Paste token',
                ),
              ),
            ),
            Padding(
              padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
              child: FilledButton(
                onPressed: _saving ? null : _saveToken,
                style: FilledButton.styleFrom(
                  backgroundColor: fs.accent,
                  foregroundColor: fs.parchment,
                ),
                child: Text(_saving ? 'Saving…' : 'Save token'),
              ),
            ),
            SwitchListTile(
              title: Text(
                'Send my plays to ListenBrainz',
                style: TextStyle(color: fs.parchment),
              ),
              subtitle: s.lastScrobbledAt != null
                  ? Text(
                      'Last scrobble: ${s.lastScrobbledAt}',
                      style: TextStyle(color: fs.ash, fontSize: 11),
                    )
                  : null,
              value: s.enabled,
              activeThumbColor: fs.accent,
              onChanged: s.tokenSet ? _toggleEnabled : null,
            ),
          ],
        ),
      ),
    ]);
  }
}

InputDecoration _inputDecoration(FabledSwordTheme fs, String label) {
  return InputDecoration(
    labelText: label,
    labelStyle: TextStyle(color: fs.ash),
    enabledBorder: OutlineInputBorder(
      borderSide: BorderSide(color: fs.iron),
    ),
    focusedBorder: OutlineInputBorder(
      borderSide: BorderSide(color: fs.accent),
    ),
  );
}

class _AppearanceSection extends ConsumerWidget {
  const _AppearanceSection();

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final fs = Theme.of(context).extension<FabledSwordTheme>()!;
    final current = ref.watch(themeModeProvider).value ?? AppThemeMode.system;
    // RadioGroup is the post-Flutter-3.32 API: the ancestor owns
    // groupValue/onChanged so individual RadioListTiles don't have
    // to repeat them. Pre-3.32 RadioListTile.groupValue/onChanged
    // are deprecated.
    return RadioGroup<AppThemeMode>(
      groupValue: current,
      onChanged: (m) {
        if (m != null) {
          ref.read(themeModeProvider.notifier).set(m);
        }
      },
      child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
        const _SectionHeader('Appearance'),
        for (final mode in AppThemeMode.values)
          RadioListTile<AppThemeMode>(
            key: Key('appearance_${mode.name}'),
            title: Text(_label(mode), style: TextStyle(color: fs.parchment)),
            subtitle: mode == AppThemeMode.system
                ? Text('Match the device setting',
                    style: TextStyle(color: fs.ash))
                : null,
            value: mode,
            activeColor: fs.accent,
          ),
      ]),
    );
  }

  String _label(AppThemeMode m) => switch (m) {
        AppThemeMode.system => 'System',
        AppThemeMode.light => 'Light',
        AppThemeMode.dark => 'Dark',
      };
}
