// ChainModuleSheet — modal bottom-sheet showing detailed module
// info: full capability list, declared permissions, on-disk
// directory. Opened by tapping a module card on the Modules
// page.

import 'package:flutter/material.dart';

import '../data/error_presentation.dart';
import '../data/hub.dart';
import '../l10n/app_localizations.dart';
import '../pages/welcome.dart' show showFaiDoc;
import '../theme/theme.dart';
import '../theme/tokens.dart';
import 'chain_pill.dart';

class ChainModuleSheet extends StatefulWidget {
  final String moduleName;

  const ChainModuleSheet({super.key, required this.moduleName});

  /// Convenience launcher used from the Modules list. Resolves
  /// to `true` when the operator uninstalled the module — the
  /// caller (Modules page) refreshes its list on that signal.
  static Future<bool> show(BuildContext context, String name) async {
    final r = await showModalBottomSheet<bool>(
      context: context,
      backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
      isScrollControlled: true,
      elevation: 8,
      shape: const RoundedRectangleBorder(
        borderRadius: BorderRadius.vertical(top: Radius.circular(ChainRadius.md)),
      ),
      builder: (_) => ChainModuleSheet(moduleName: name),
    );
    return r ?? false;
  }

  @override
  State<ChainModuleSheet> createState() => _FaiModuleSheetState();
}

class _FaiModuleSheetState extends State<ChainModuleSheet> {
  late final Future<ModuleDetail> _future;
  bool _uninstalling = false;

  @override
  void initState() {
    super.initState();
    _future = HubService.instance.moduleInfo(widget.moduleName);
  }

  Future<void> _confirmAndUninstall(ModuleDetail detail) async {
    final l = AppLocalizations.of(context)!;
    // When more than one version of the same module is
    // installed side-by-side, ask the operator which one to
    // remove. The hub's uninstall RPC otherwise falls back to
    // "remove the highest version", which is rarely what an
    // operator means when they've explicitly kept multiple
    // versions around.
    final versions = await HubService.instance.installedVersions(detail.name);
    if (!mounted) return;
    String? targetVersion;
    if (versions.length > 1) {
      targetVersion = await showDialog<String>(
        context: context,
        builder: (ctx) => _UninstallVersionPickerDialog(
          moduleName: detail.name,
          versions: versions,
        ),
      );
      if (targetVersion == null || !mounted) return;
    }
    final displayVersion = targetVersion ?? detail.version;
    final ok = await showDialog<bool>(
      context: context,
      builder: (ctx) => AlertDialog(
        title: Text(l.modulesUninstallTitle),
        content: Text(l.modulesUninstallBody(detail.name, displayVersion)),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(ctx, false),
            child: Text(l.buttonCancel),
          ),
          FilledButton(
            onPressed: () => Navigator.pop(ctx, true),
            style: FilledButton.styleFrom(
              backgroundColor: Theme.of(ctx).colorScheme.error,
              foregroundColor: Theme.of(ctx).colorScheme.onError,
            ),
            child: Text(l.buttonUninstall),
          ),
        ],
      ),
    );
    if (ok != true || !mounted) return;
    setState(() => _uninstalling = true);
    try {
      final r = await HubService.instance.uninstallModule(
        detail.name,
        version: targetVersion ?? '',
      );
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text(l.modulesUninstalledToast(r.name, r.version))),
      );
      Navigator.pop(context, true);
    } catch (e) {
      if (!mounted) return;
      setState(() => _uninstalling = false);
      showFaiErrorSnack(context, 'modules.uninstall', e);
    }
  }

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final maxHeight = MediaQuery.of(context).size.height * 0.7;

    return ConstrainedBox(
      constraints: BoxConstraints(maxHeight: maxHeight),
      child: FutureBuilder<ModuleDetail>(
        future: _future,
        builder: (context, snapshot) {
          return Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              _Handle(),
              if (snapshot.connectionState == ConnectionState.waiting)
                const Padding(
                  padding: EdgeInsets.all(ChainSpace.xxxl),
                  child: CircularProgressIndicator(),
                )
              else if (snapshot.hasError)
                Padding(
                  padding: const EdgeInsets.all(ChainSpace.xl),
                  child: Text(
                    AppLocalizations.of(
                      context,
                    )!.moduleSheetFailedToLoad(snapshot.error.toString()),
                    style: theme.textTheme.bodyMedium?.copyWith(
                      color: theme.colorScheme.error,
                    ),
                  ),
                )
              else
                Flexible(
                  child: _Body(
                    detail: snapshot.data!,
                    uninstalling: _uninstalling,
                    onUninstall: () => _confirmAndUninstall(snapshot.data!),
                  ),
                ),
            ],
          );
        },
      ),
    );
  }
}

class _Handle extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: ChainSpace.sm),
      child: Container(
        width: 40,
        height: 4,
        decoration: BoxDecoration(
          color: theme.colorScheme.outlineVariant,
          borderRadius: BorderRadius.circular(2),
        ),
      ),
    );
  }
}

class _Body extends StatelessWidget {
  final ModuleDetail detail;
  final bool uninstalling;
  final VoidCallback onUninstall;

  const _Body({
    required this.detail,
    required this.uninstalling,
    required this.onUninstall,
  });

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final l = AppLocalizations.of(context)!;
    return ListView(
      padding: const EdgeInsets.fromLTRB(
        ChainSpace.xxl,
        ChainSpace.md,
        ChainSpace.xxl,
        ChainSpace.xxl,
      ),
      shrinkWrap: true,
      children: [
        Row(
          children: [
            Text(
              detail.name,
              style: theme.textTheme.headlineSmall?.copyWith(
                fontWeight: FontWeight.w600,
              ),
            ),
            const SizedBox(width: ChainSpace.md),
            ChainPill(
              label: 'v${detail.version}',
              tone: ChainPillTone.accent,
              monospace: true,
            ),
          ],
        ),
        const SizedBox(height: ChainSpace.xs),
        SelectableText(
          detail.directory,
          style: ChainTheme.mono(
            size: 11,
            color: theme.colorScheme.onSurfaceVariant,
          ),
        ),
        const SizedBox(height: ChainSpace.xl),
        _SectionHeader(l.moduleSheetCapabilities),
        const SizedBox(height: ChainSpace.sm),
        Wrap(
          spacing: ChainSpace.xs,
          runSpacing: ChainSpace.xs,
          children: detail.capabilities
              .map(
                (c) => ChainPill(
                  label: c,
                  tone: ChainPillTone.accent,
                  monospace: true,
                ),
              )
              .toList(),
        ),
        const SizedBox(height: ChainSpace.xl),
        Row(
          children: [
            _SectionHeader(l.moduleSheetPermissions),
            const SizedBox(width: 4),
            InkWell(
              onTap: () => showFaiDoc(context, 'security'),
              borderRadius: BorderRadius.circular(8),
              child: Padding(
                padding: const EdgeInsets.all(4),
                child: Icon(
                  Icons.help_outline,
                  size: 14,
                  color: theme.colorScheme.onSurfaceVariant,
                ),
              ),
            ),
          ],
        ),
        const SizedBox(height: ChainSpace.sm),
        if (detail.permissions.isEmpty)
          Text(
            l.moduleSheetNoPermissions,
            style: theme.textTheme.bodySmall?.copyWith(
              color: theme.colorScheme.onSurfaceVariant,
              fontStyle: FontStyle.italic,
            ),
          )
        else
          Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: detail.permissions
                .map(
                  (p) => Padding(
                    padding: const EdgeInsets.symmetric(vertical: 2),
                    child: Row(
                      children: [
                        Icon(
                          _iconFor(p),
                          size: 14,
                          color: theme.colorScheme.onSurfaceVariant,
                        ),
                        const SizedBox(width: ChainSpace.sm),
                        SelectableText(
                          p,
                          style: ChainTheme.mono(
                            size: 12,
                            color: theme.colorScheme.onSurface,
                          ),
                        ),
                      ],
                    ),
                  ),
                )
                .toList(),
          ),
        const SizedBox(height: ChainSpace.xxl),
        Row(
          children: [
            const Spacer(),
            OutlinedButton.icon(
              onPressed: uninstalling ? null : onUninstall,
              icon: uninstalling
                  ? const SizedBox(
                      width: 14,
                      height: 14,
                      child: CircularProgressIndicator(strokeWidth: 2),
                    )
                  : const Icon(Icons.delete_outline, size: 16),
              label: Text(
                uninstalling
                    ? AppLocalizations.of(context)!.modulesUninstalling
                    : AppLocalizations.of(context)!.buttonUninstall,
              ),
              style: OutlinedButton.styleFrom(
                foregroundColor: theme.colorScheme.error,
                side: BorderSide(
                  color: theme.colorScheme.error.withValues(alpha: 0.5),
                ),
              ),
            ),
          ],
        ),
      ],
    );
  }

  IconData _iconFor(String permission) {
    if (permission.startsWith('net:')) return Icons.public;
    if (permission.startsWith('fs.read:')) return Icons.folder_open;
    if (permission.startsWith('fs.write:')) return Icons.edit_note;
    if (permission.startsWith('env:')) return Icons.terminal;
    if (permission.startsWith('hub:')) return Icons.shield_outlined;
    return Icons.lock_outline;
  }
}

/// Modal that asks the operator to pick which installed
/// version to uninstall when more than one version of the same
/// `(provider, name)` is on disk side-by-side. Pops the picked
/// version string, or `null` on cancel.
class _UninstallVersionPickerDialog extends StatefulWidget {
  final String moduleName;
  final List<String> versions;

  const _UninstallVersionPickerDialog({
    required this.moduleName,
    required this.versions,
  });

  @override
  State<_UninstallVersionPickerDialog> createState() =>
      _UninstallVersionPickerDialogState();
}

class _UninstallVersionPickerDialogState
    extends State<_UninstallVersionPickerDialog> {
  late String _picked;

  @override
  void initState() {
    super.initState();
    // Default to the highest version — same fallback the hub
    // would pick without an explicit version, so the operator
    // can confirm with one click in the common case.
    _picked = widget.versions.last;
  }

  @override
  Widget build(BuildContext context) {
    final l = AppLocalizations.of(context)!;
    return AlertDialog(
      title: Text(l.uninstallVersionPickerTitle),
      content: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        children: [
          Text(l.uninstallVersionPickerBody(widget.moduleName)),
          const SizedBox(height: ChainSpace.md),
          RadioGroup<String>(
            groupValue: _picked,
            onChanged: (val) {
              if (val != null) setState(() => _picked = val);
            },
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                for (final v in widget.versions)
                  RadioListTile<String>(
                    value: v,
                    title: Text(
                      'v$v',
                      style: const TextStyle(fontFamily: 'monospace'),
                    ),
                    dense: true,
                    contentPadding: EdgeInsets.zero,
                  ),
              ],
            ),
          ),
        ],
      ),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context),
          child: Text(l.buttonCancel),
        ),
        FilledButton(
          onPressed: () => Navigator.pop(context, _picked),
          child: Text(l.uninstallVersionPickerContinue),
        ),
      ],
    );
  }
}

class _SectionHeader extends StatelessWidget {
  final String text;

  const _SectionHeader(this.text);

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return Text(
      text.toUpperCase(),
      style: theme.textTheme.labelSmall?.copyWith(
        color: theme.colorScheme.onSurfaceVariant,
        letterSpacing: 0.6,
        fontSize: 10,
      ),
    );
  }
}
