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

import '../../../../api/errors/error_mapper.dart';
import '../../../../api/marianumcloud/files_sharing/file_sharing_api.dart';
import '../../../../api/marianumcloud/files_sharing/file_sharing_api_params.dart';
import '../../../../api/marianumcloud/files_sharing/ocs_path.dart';
import '../../../../api/marianumcloud/files_sharing/queries/share/share.dart';
import '../../../../api/marianumcloud/files_sharing/share_permissions.dart';
import '../../../../api/marianumcloud/webdav/queries/list_files/cacheable_file.dart';
import '../../../../routing/app_routes.dart';
import '../../../../state/app/modules/nextcloud_capabilities/bloc/nextcloud_capabilities_cubit.dart';
import '../../../../utils/clipboard_helper.dart';
import '../../../../widget/app_progress_indicator.dart';
import '../../../../widget/centered_leading.dart';
import '../../../../widget/demo_restricted.dart';
import '../../../../widget/details_bottom_sheet.dart';
import '../../../../widget/info_dialog.dart';
import '../widgets/file_leading.dart';
import 'share_options_sheet.dart';
import 'share_password_sheet.dart';

/// Opens the sharing sheet for a file/folder: lists existing shares and offers
/// gated actions to create new ones (public link, user/group). Capability
/// gating mirrors the Nextcloud web UI.
void showShareSheet(BuildContext context, CacheableFile file) {
  if (guardDemoAction(context)) return;
  showDetailsBottomSheet(
    context,
    header: ListTile(
      leading: CenteredLeading(FileLeading(file: file)),
      title: Text(file.name),
      subtitle: const Text('Freigeben'),
    ),
    children: (sheetCtx) => [_ShareSheetBody(file: file)],
  );
}

class _ShareSheetBody extends StatefulWidget {
  final CacheableFile file;

  const _ShareSheetBody({required this.file});

  @override
  State<_ShareSheetBody> createState() => _ShareSheetBodyState();
}

class _ShareSheetBodyState extends State<_ShareSheetBody> {
  late final String _ocsPath = ocsPathOf(widget.file);
  Future<List<Share>>? _future;
  bool _busy = false;

  /// Last resolved share list — used by the create-link gate without depending
  /// on the FutureBuilder's snapshot.
  List<Share>? _lastShares;

  @override
  void initState() {
    super.initState();
    _future = FileSharingApi().listForPath(_ocsPath);
  }

  void _reload() {
    // Block body: an arrow would return the Future, which setState rejects.
    setState(() {
      _future = FileSharingApi().listForPath(_ocsPath);
    });
  }

  Future<void> _runCreate(FileSharingApiParams params) async {
    setState(() => _busy = true);
    try {
      await FileSharingApi().share(params);
      if (!mounted) return;
      _reload();
    } catch (e) {
      if (mounted) {
        InfoDialog.show(
          context,
          errorToUserMessage(e),
          title: 'Freigabe fehlgeschlagen',
          copyable: true,
        );
      }
    } finally {
      if (mounted) setState(() => _busy = false);
    }
  }

  Future<void> _createPublicLink() async {
    final caps = context.read<NextcloudCapabilitiesCubit>();
    String? password;
    if (caps.passwordEnforced) {
      // The server requires a password — collect it before creating, otherwise
      // the call is rejected.
      password = await promptSharePassword(
        context,
        isChange: false,
        policyHint: caps.passwordPolicyHint,
      );
      if (password == null || password.isEmpty || !mounted) return;
    }
    await _runCreate(
      FileSharingApiParams(
        shareType: kShareTypePublicLink,
        shareWith: '',
        path: _ocsPath,
        permissions: kPermissionRead,
        password: password,
      ),
    );
  }

  Future<void> _addSharee() async {
    final caps = context.read<NextcloudCapabilitiesCubit>();
    final sharee = await AppRoutes.openShareePicker(
      context,
      allowUsers: caps.canShareWithUsers,
      allowGroups: caps.canShareWithGroups,
    );
    if (sharee == null || !mounted) return;
    await _runCreate(
      FileSharingApiParams(
        shareType: sharee.shareType,
        shareWith: sharee.shareWith,
        path: _ocsPath,
        permissions: kPermissionRead,
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    final caps = context.watch<NextcloudCapabilitiesCubit>();
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      mainAxisSize: MainAxisSize.min,
      children: [
        if (_busy) const LinearProgressIndicator(),
        _shareList(),
        const Divider(height: 1),
        if (caps.canShareWithUsers || caps.canShareWithGroups)
          ListTile(
            leading: const CenteredLeading(Icon(Icons.person_add_outlined)),
            title: const Text('Person oder Gruppe hinzufügen'),
            enabled: !_busy,
            onTap: _busy ? null : _addSharee,
          ),
        if (caps.canCreatePublicLinks && _canAddLink(caps))
          ListTile(
            leading: const CenteredLeading(Icon(Icons.add_link)),
            title: const Text('Öffentlichen Link erstellen'),
            enabled: !_busy,
            onTap: _busy ? null : _createPublicLink,
          ),
      ],
    );
  }

  void _openInTalk(Share share) {
    final token = share.shareWith;
    if (token == null || token.isEmpty) return;
    AppRoutes.openChatByToken(context, token);
    if (Navigator.of(context).canPop()) Navigator.of(context).pop();
  }

  /// Whether another public link may be created — hidden once one exists on a
  /// server that disallows multiple links.
  bool _canAddLink(NextcloudCapabilitiesCubit caps) {
    if (caps.allowsMultipleLinks) return true;
    final hasLink = _lastShares?.any((s) => s.isPublicLink) ?? false;
    return !hasLink;
  }

  Widget _shareList() {
    return FutureBuilder<List<Share>>(
      future: _future,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const Padding(
            padding: EdgeInsets.all(24),
            child: Center(child: AppProgressIndicator.medium()),
          );
        }
        if (snapshot.hasError) {
          return Padding(
            padding: const EdgeInsets.all(24),
            child: Column(
              children: [
                Text(
                  errorToUserMessage(snapshot.error),
                  textAlign: TextAlign.center,
                ),
                const SizedBox(height: 12),
                FilledButton.tonal(
                  onPressed: _reload,
                  child: const Text('Erneut versuchen'),
                ),
              ],
            ),
          );
        }
        final shares = snapshot.data ?? const <Share>[];
        _lastShares = shares;
        if (shares.isEmpty) {
          final theme = Theme.of(context);
          return SizedBox(
            height: 160,
            child: Center(
              child: Padding(
                padding: const EdgeInsets.symmetric(horizontal: 24),
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Icon(
                      Icons.lock_outline,
                      size: 48,
                      color: theme.colorScheme.outline,
                    ),
                    const SizedBox(height: 12),
                    Text(
                      'Diese Datei ist noch nicht freigegeben.',
                      textAlign: TextAlign.center,
                      style: theme.textTheme.bodyLarge?.copyWith(
                        color: theme.colorScheme.onSurfaceVariant,
                      ),
                    ),
                  ],
                ),
              ),
            ),
          );
        }
        return Column(
          mainAxisSize: MainAxisSize.min,
          children: shares.map(_shareTile).toList(),
        );
      },
    );
  }

  Widget _shareTile(Share share) {
    final preset = presetFromBitmask(share.permissions);
    final subtitleParts = <String>[
      // For links the URL already identifies the row; for everyone else show
      // the kind so a Talk share isn't mistaken for a plain person share.
      if (share.isPublicLink && share.url != null)
        share.url!
      else
        share.kindLabel,
      if (preset != null) preset.label,
      if (share.hasPassword) 'passwortgeschützt',
      if (share.expiration != null) 'bis ${share.expiration}',
    ];
    return ListTile(
      leading: CenteredLeading(Icon(shareIcon(share))),
      title: Text(share.displayTitle),
      subtitle: subtitleParts.isEmpty
          ? null
          : Text(
              subtitleParts.join(' · '),
              maxLines: 1,
              overflow: TextOverflow.ellipsis,
            ),
      trailing: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          if (share.isPublicLink && share.url != null)
            IconButton(
              icon: const Icon(Icons.copy_outlined),
              tooltip: 'Link kopieren',
              onPressed: () => copyToClipboard(context, share.url!),
            ),
          if (share.isRoom && (share.shareWith?.isNotEmpty ?? false))
            IconButton(
              icon: const Icon(Icons.chat_bubble_outline),
              tooltip: 'Im Talk-Chat öffnen',
              onPressed: () => _openInTalk(share),
            ),
          IconButton(
            icon: const Icon(Icons.settings_outlined),
            tooltip: 'Freigabe bearbeiten',
            onPressed: () =>
                showShareOptionsSheet(context, share, onChanged: _reload),
          ),
        ],
      ),
    );
  }
}
