import 'dart:io';

import 'package:file_selector/file_selector.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:forui/forui.dart';
import 'package:url_launcher/url_launcher.dart';

import '../../../shared/utils/format_utils.dart';

import '../../../providers/appearance_provider.dart';
import '../../../providers/danmaku_settings_provider.dart';
import '../../../providers/di_providers.dart';
import '../../../providers/server_provider.dart';
import '../../../providers/session_provider.dart';
import '../../../providers/sm_account_provider.dart';
import '../../../providers/update_provider.dart';
import '../../../shared/app_info.dart';
import '../../../shared/theme/app_theme.dart';
import '../../../shared/utils/user_error_formatter.dart';
import '../../../shared/widgets/app_inline_alert.dart';
import '../../../shared/widgets/app_loading_ring.dart';
import '../../../shared/widgets/setting_select.dart';
import '../../account/account_center_page.dart';
import '../utils/settings_labels.dart';
import '../widgets/settings_card.dart';

class GeneralSettingsTab extends ConsumerStatefulWidget {
  final void Function(String message, {AppAlertTone tone}) onFeedback;

  const GeneralSettingsTab({super.key, required this.onFeedback});

  @override
  ConsumerState<GeneralSettingsTab> createState() => _GeneralSettingsTabState();
}

class _GeneralSettingsTabState extends ConsumerState<GeneralSettingsTab> {
  bool _installTriggered = false;

  @override
  Widget build(BuildContext context) {
    final appearance = ref.watch(appearanceProvider);
    final updateState = ref.watch(updateProvider);
    final appVersion =
        ref.watch(appVersionProvider).value ?? kSmPlayerVersionFallback;

    if (updateState.status != UpdateStatus.readyToInstall) {
      _installTriggered = false;
    } else if (!updateState.silent && !_installTriggered) {
      _installTriggered = true;
      WidgetsBinding.instance.addPostFrameCallback((_) {
        if (!mounted) return;
        ref.read(updateProvider.notifier).install();
      });
    }

    final account = ref.watch(smAccountProvider).value;

    return SettingsTabScroll(
      children: [
        SettingsCard(
          children: [
            SettingRow(
              title: account?.loggedIn == true
                  ? (account!.email.isNotEmpty ? account.email : 'Player 账号')
                  : '账号',
              subtitle: account?.loggedIn == true ? null : '登录以使用云同步等服务',
              trailing: const Icon(Icons.chevron_right, size: 18),
              onTap: _openAccountSheet,
            ),
          ],
        ),
        appearance.when(
          data: (data) => SettingsCard(
            children: [
              SettingRow(
                title: '主题模式',
                trailing: SettingSelect<ThemeMode>(
                  value: data.themeMode,
                  options: ThemeMode.values,
                  labelOf: themeModeLabel,
                  onChanged: (v) {
                    if (v != null) {
                      ref.read(appearanceProvider.notifier).setThemeMode(v);
                    }
                  },
                ),
              ),
              SettingRow(
                title: '顶栏背景',
                trailing: SettingSelect<HeaderMode>(
                  value: data.headerMode,
                  options: HeaderMode.values,
                  labelOf: headerModeLabel,
                  onChanged: (v) {
                    if (v != null) {
                      ref.read(appearanceProvider.notifier).setHeaderMode(v);
                    }
                  },
                ),
              ),
              SettingRow(
                title: '启动页面',
                subtitle: '下次打开软件时进入的页面',
                trailing: SettingSelect<StartupPage>(
                  value: data.startupPage,
                  options: StartupPage.values,
                  labelOf: startupPageLabel,
                  onChanged: (v) {
                    if (v != null) {
                      ref.read(appearanceProvider.notifier).setStartupPage(v);
                    }
                  },
                ),
              ),
            ],
          ),
          loading: () => const SizedBox.shrink(),
          error: (e, _) => settingsLoadError(e),
        ),
        SettingsCard(
          children: [
            SettingRow(
              title: '检查更新',
              subtitle: _updateStatusText(updateState, appVersion),
              trailing: FilledButton.tonalIcon(
                onPressed: _canManualCheck(updateState)
                    ? _manualCheckUpdate
                    : null,
                icon:
                    updateState.status == UpdateStatus.checking &&
                        !updateState.silent
                    ? const AppLoadingRing(size: 14)
                    : const Icon(Icons.system_update_alt_rounded, size: 16),
                label: const Text('检查更新'),
              ),
            ),
            if (_shouldShowInlineUpdate(updateState))
              _InlineUpdatePanel(
                state: updateState,
                appVersion: appVersion,
                onCheckAgain: _manualCheckUpdate,
                onDownload: () =>
                    ref.read(updateProvider.notifier).startDownload(),
                onCancel: () => ref.read(updateProvider.notifier).cancel(),
                onOpenDownloadPage: _openDownloadPage,
              ),
          ],
        ),
        SettingsCard(
          children: [
            SettingRow(
              title: '导出到文件',
              trailing: const Icon(Icons.upload_file, size: 18),
              onTap: () => _exportBackup(context),
            ),
            SettingRow(
              title: '从文件导入',
              trailing: const Icon(Icons.download, size: 18),
              onTap: () => _importBackup(context),
            ),
          ],
        ),
      ],
    );
  }

  bool _canManualCheck(UpdateState state) {
    return state.status != UpdateStatus.checking &&
        state.status != UpdateStatus.downloading &&
        state.status != UpdateStatus.readyToInstall;
  }

  bool _shouldShowInlineUpdate(UpdateState state) {
    if (state.silent) return false;
    return state.status != UpdateStatus.idle;
  }

  String _updateStatusText(UpdateState state, String appVersion) {
    if (!state.silent) {
      switch (state.status) {
        case UpdateStatus.checking:
          return '当前版本 $appVersion，正在检查';
        case UpdateStatus.upToDate:
          return '当前版本 $appVersion，已是最新版本';
        case UpdateStatus.error:
          return '当前版本 $appVersion，${state.error ?? '检查失败'}';
        case UpdateStatus.available:
          return '当前版本 $appVersion，发现新版本 ${state.info?.version ?? ''}';
        case UpdateStatus.downloading:
          return '当前版本 $appVersion，正在下载更新';
        case UpdateStatus.readyToInstall:
          return '当前版本 $appVersion，正在打开安装程序';
        case UpdateStatus.idle:
          break;
      }
    }
    return '当前版本 $appVersion';
  }

  Future<void> _manualCheckUpdate() async {
    await ref.read(updateProvider.notifier).manualCheck();
  }

  Future<void> _openDownloadPage(Uri uri) async {
    if (!uri.hasScheme) return;
    await launchUrl(uri, mode: LaunchMode.externalApplication);
  }

  Future<void> _openAccountSheet() async {
    final message = await showAccountCenterSheet(context);
    if (!mounted || message == null || message.isEmpty) return;
    widget.onFeedback(message, tone: AppAlertTone.success);
  }

  Future<void> _exportBackup(BuildContext context) async {
    try {
      final location = await getSaveLocation(
        suggestedName: _backupFileName(DateTime.now()),
        acceptedTypeGroups: const [
          XTypeGroup(label: 'JSON', extensions: ['json']),
        ],
      );
      if (location == null) return;

      final usecase = await ref.read(exportBackupUseCaseProvider.future);
      final result = await usecase.execute();
      await File(location.path).writeAsString(result.json, flush: true);

      if (!context.mounted) return;
      widget.onFeedback(
        '已导出 ${result.serverCount} 个服务器、${result.sessionCount} 个登录态、'
        '${result.danmakuSourceCount} 个弹幕源、'
        '${result.scriptWidgetCount} 个模块、${result.scriptWidgetSubscriptionCount} 个订阅。'
        '备份文件含登录凭据与模块用户参数，请妥善保管。',
        tone: AppAlertTone.success,
      );
    } catch (e) {
      if (!context.mounted) return;
      widget.onFeedback('导出失败：${formatUserError(e)}', tone: AppAlertTone.error);
    }
  }

  Future<void> _importBackup(BuildContext context) async {
    try {
      final file = await openFile(
        acceptedTypeGroups: const [
          XTypeGroup(label: 'JSON', extensions: ['json']),
        ],
      );
      if (file == null) return;

      final raw = await File(file.path).readAsString();
      final usecase = await ref.read(importBackupUseCaseProvider.future);
      final result = await usecase.execute(raw);

      await ref.read(serverListProvider.notifier).refresh();
      await ref.read(sessionProvider.notifier).refresh();
      ref.invalidate(danmakuSettingsProvider);
      ref.invalidate(installedScriptWidgetsProvider);
      ref.invalidate(scriptWidgetSubscriptionsProvider);

      if (!context.mounted) return;
      widget.onFeedback(
        '已导入 ${result.serverCount} 个服务器、${result.sessionCount} 个登录态、'
        '${result.danmakuSourceCount} 个弹幕源、'
        '${result.scriptWidgetCount} 个模块、${result.scriptWidgetSubscriptionCount} 个订阅',
        tone: AppAlertTone.success,
      );
    } catch (e) {
      if (!context.mounted) return;
      widget.onFeedback('导入失败：${formatUserError(e)}', tone: AppAlertTone.error);
    }
  }

  static String _backupFileName(DateTime now) {
    String two(int v) => v.toString().padLeft(2, '0');
    return 'smplayer-backup-${now.year}${two(now.month)}${two(now.day)}'
        '-${two(now.hour)}${two(now.minute)}.json';
  }
}

class _InlineUpdatePanel extends StatelessWidget {
  final UpdateState state;
  final String appVersion;
  final VoidCallback onCheckAgain;
  final VoidCallback onDownload;
  final VoidCallback onCancel;
  final ValueChanged<Uri> onOpenDownloadPage;

  const _InlineUpdatePanel({
    required this.state,
    required this.appVersion,
    required this.onCheckAgain,
    required this.onDownload,
    required this.onCancel,
    required this.onOpenDownloadPage,
  });

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final tokens = context.appTokens;
    final info = state.info;
    final isChecking = state.status == UpdateStatus.checking;
    final isUpToDate = state.status == UpdateStatus.upToDate;
    final isError = state.status == UpdateStatus.error;
    final isDownloading = state.status == UpdateStatus.downloading;
    final isReady = state.status == UpdateStatus.readyToInstall;

    return Padding(
      padding: const EdgeInsets.fromLTRB(16, 14, 16, 16),
      child: AnimatedSwitcher(
        duration: const Duration(milliseconds: 180),
        child: Column(
          key: ValueKey(state.status),
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            if (isChecking)
              _StatusLine(
                icon: Icons.sync_rounded,
                iconColor: tokens.mutedForeground,
                text: '正在检查更新...',
              )
            else if (isUpToDate)
              _StatusLine(
                icon: Icons.check_circle_outline_rounded,
                iconColor: Colors.green,
                text: '当前版本 $appVersion 已是最新版本。',
              )
            else if (isError)
              _ErrorBlock(
                message: state.error ?? '检查更新失败，请稍后重试',
                onRetry: onCheckAgain,
              )
            else if (info != null) ...[
              Text(
                '发现新版本 ${info.version}',
                style: theme.textTheme.titleSmall?.copyWith(
                  fontWeight: FontWeight.w600,
                ),
              ),
              const SizedBox(height: 4),
              Text(
                '当前版本 $appVersion → 最新版本 ${info.version}',
                style: theme.textTheme.bodySmall?.copyWith(
                  color: tokens.mutedForeground,
                ),
              ),
              const SizedBox(height: 12),
              ConstrainedBox(
                constraints: const BoxConstraints(maxHeight: 150),
                child: SingleChildScrollView(
                  child: Text(
                    info.releaseNotes.trim().isEmpty
                        ? '暂无更新说明'
                        : info.releaseNotes.trim(),
                    style: theme.textTheme.bodySmall?.copyWith(height: 1.45),
                  ),
                ),
              ),
              if (isDownloading) ...[
                const SizedBox(height: 16),
                FDeterminateProgress(
                  value: downloadProgressValue(
                    received: state.received,
                    total: state.total,
                  ) ?? 0,
                ),
                const SizedBox(height: 8),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Text(
                      '${formatDownloadBytes(state.received)} / ${formatDownloadBytes(state.total)}',
                      style: theme.textTheme.bodySmall?.copyWith(
                        color: tokens.mutedForeground,
                      ),
                    ),
                    Text(
                      formatDownloadSpeed(state.speedBytesPerSec),
                      style: theme.textTheme.bodySmall?.copyWith(
                        color: tokens.mutedForeground,
                      ),
                    ),
                  ],
                ),
              ],
              if (isReady) ...[
                const SizedBox(height: 16),
                _StatusLine(
                  icon: Icons.install_desktop_rounded,
                  iconColor: tokens.mutedForeground,
                  text: '安装程序已下载，正在打开。',
                ),
              ],
              const SizedBox(height: 14),
              Wrap(
                spacing: 8,
                runSpacing: 8,
                children: [
                  if (isDownloading)
                    OutlinedButton(
                      onPressed: onCancel,
                      child: const Text('取消下载'),
                    )
                  else if (info.noAssetForPlatform)
                    FilledButton.tonalIcon(
                      onPressed: () => onOpenDownloadPage(info.htmlUrl),
                      icon: const Icon(Icons.open_in_new_rounded, size: 16),
                      label: const Text('前往下载页'),
                    )
                  else
                    FilledButton.tonalIcon(
                      onPressed: isReady ? null : onDownload,
                      icon: const Icon(Icons.download_rounded, size: 16),
                      label: const Text('下载并安装'),
                    ),
                  TextButton(
                    onPressed: isDownloading || isReady ? null : onCheckAgain,
                    child: const Text('重新检查'),
                  ),
                ],
              ),
            ],
          ],
        ),
      ),
    );
  }
}

class _StatusLine extends StatelessWidget {
  final IconData icon;
  final Color iconColor;
  final String text;

  const _StatusLine({
    required this.icon,
    required this.iconColor,
    required this.text,
  });

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        Icon(icon, size: 18, color: iconColor),
        const SizedBox(width: 8),
        Expanded(child: Text(text)),
      ],
    );
  }
}

class _ErrorBlock extends StatelessWidget {
  final String message;
  final VoidCallback onRetry;

  const _ErrorBlock({required this.message, required this.onRetry});

  @override
  Widget build(BuildContext context) {
    final color = Theme.of(context).colorScheme.error;
    return Row(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Icon(Icons.error_outline_rounded, size: 18, color: color),
        const SizedBox(width: 8),
        Expanded(
          child: Text(message, style: TextStyle(color: color)),
        ),
        const SizedBox(width: 8),
        TextButton(onPressed: onRetry, child: const Text('重试')),
      ],
    );
  }
}
