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/queries/share/share.dart';
import '../../../../api/marianumcloud/files_sharing/queries/share/share_update_params.dart';
import '../../../../api/marianumcloud/files_sharing/share_permissions.dart';
import '../../../../routing/app_routes.dart';
import '../../../../state/app/modules/nextcloud_capabilities/bloc/nextcloud_capabilities_cubit.dart';
import '../../../../utils/clipboard_helper.dart';
import '../../../../widget/centered_leading.dart';
import '../../../../widget/confirm_dialog.dart';
import '../../../../widget/demo_restricted.dart';
import '../../../../widget/details_bottom_sheet.dart';
import '../../../../widget/info_dialog.dart';
import 'share_password_sheet.dart';

/// Two-digit zero-padded helper for building ISO `YYYY-MM-DD` strings (the
/// format the OCS API expects for `expireDate`).
String _two(int n) => n.toString().padLeft(2, '0');
String _isoDate(DateTime d) => '${d.year}-${_two(d.month)}-${_two(d.day)}';

IconData shareIcon(Share share) {
  if (share.isPublicLink) return Icons.link;
  if (share.isGroup) return Icons.groups_outlined;
  if (share.isRoom) return Icons.chat_bubble_outline;
  if (share.isEmail) return Icons.email_outlined;
  return Icons.person_outline;
}

/// Opens the edit/manage sheet for a single [share]. [onChanged] fires after
/// every successful mutation so the parent share list can refresh.
void showShareOptionsSheet(
  BuildContext context,
  Share share, {
  required VoidCallback onChanged,
}) {
  if (guardDemoAction(context)) return;
  showDetailsBottomSheet(
    context,
    header: ListTile(
      leading: CenteredLeading(Icon(shareIcon(share))),
      title: Text(share.displayTitle),
      subtitle: Text(share.kindLabel),
    ),
    children: (sheetCtx) => [
      _ShareOptionsBody(share: share, onChanged: onChanged),
    ],
  );
}

class _ShareOptionsBody extends StatefulWidget {
  final Share share;
  final VoidCallback onChanged;

  const _ShareOptionsBody({required this.share, required this.onChanged});

  @override
  State<_ShareOptionsBody> createState() => _ShareOptionsBodyState();
}

class _ShareOptionsBodyState extends State<_ShareOptionsBody> {
  late Share _share = widget.share;
  bool _busy = false;

  Future<void> _mutate(Future<Share> Function() action) async {
    setState(() => _busy = true);
    try {
      final updated = await action();
      if (!mounted) return;
      setState(() => _share = updated);
      widget.onChanged();
    } catch (e) {
      if (mounted) {
        InfoDialog.show(
          context,
          errorToUserMessage(e),
          title: 'Fehler',
          copyable: true,
        );
      }
    } finally {
      if (mounted) setState(() => _busy = false);
    }
  }

  List<SharePreset> _availablePresets() => [
    SharePreset.readOnly,
    SharePreset.edit,
    if (_share.isFolder) SharePreset.fileDrop,
  ];

  Future<void> _setPreset(SharePreset preset) async {
    final caps = context.read<NextcloudCapabilitiesCubit>();
    await _mutate(
      () => FileSharingApi().update(
        _share.id,
        ShareUpdateParams(
          permissions: permissionsFor(
            preset,
            allowReshare: caps.canReshare,
            isFolder: _share.isFolder,
          ),
        ),
      ),
    );
  }

  Future<void> _pickExpiry() async {
    final caps = context.read<NextcloudCapabilitiesCubit>();
    final now = DateTime.now();
    final maxDays = caps.expireDays;
    final lastDate = maxDays != null && maxDays > 0
        ? now.add(Duration(days: maxDays))
        : now.add(const Duration(days: 365 * 5));
    final picked = await showDatePicker(
      context: context,
      initialDate: now.add(const Duration(days: 7)),
      firstDate: now,
      lastDate: lastDate,
    );
    if (picked == null) return;
    await _mutate(
      () => FileSharingApi().update(
        _share.id,
        ShareUpdateParams(expireDate: _isoDate(picked)),
      ),
    );
  }

  Future<void> _clearExpiry() => _mutate(
    () => FileSharingApi().update(
      _share.id,
      const ShareUpdateParams(expireDate: ''),
    ),
  );

  Future<void> _changePassword() async {
    final caps = context.read<NextcloudCapabilitiesCubit>();
    final value = await promptSharePassword(
      context,
      isChange: _share.hasPassword,
      policyHint: caps.passwordPolicyHint,
    );
    if (value == null || value.isEmpty || !mounted) return;
    await _mutate(
      () => FileSharingApi().update(
        _share.id,
        ShareUpdateParams(password: value),
      ),
    );
  }

  Future<void> _clearPassword() => _mutate(
    () => FileSharingApi().update(
      _share.id,
      const ShareUpdateParams(password: ''),
    ),
  );

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

  Future<void> _confirmDelete() async {
    // Use showDialog directly (not asDialog) so we get the AsyncDialogAction's
    // `true` result and can close the options sheet afterwards — popping inside
    // onConfirmAsync would target the dialog route, not the sheet.
    final dialog = ConfirmDialog(
      title: 'Freigabe löschen?',
      content: 'Die Freigabe wird aufgehoben.',
      confirmButton: 'Löschen',
      onConfirmAsync: () => FileSharingApi().remove(_share.id),
    );
    final deleted = await showDialog<bool>(
      context: context,
      builder: dialog.build,
    );
    if (deleted != true || !mounted) return;
    widget.onChanged();
    if (Navigator.of(context).canPop()) Navigator.of(context).pop();
  }

  @override
  Widget build(BuildContext context) {
    final caps = context.watch<NextcloudCapabilitiesCubit>();
    final currentPreset = presetFromBitmask(_share.permissions);
    final theme = Theme.of(context);

    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      mainAxisSize: MainAxisSize.min,
      children: [
        if (_busy) const LinearProgressIndicator(),

        Padding(
          padding: const EdgeInsets.fromLTRB(16, 12, 16, 4),
          child: Text('Berechtigung', style: theme.textTheme.labelLarge),
        ),
        Padding(
          padding: const EdgeInsets.symmetric(horizontal: 16),
          child: Wrap(
            spacing: 8,
            children: _availablePresets()
                .map(
                  (p) => ChoiceChip(
                    label: Text(p.label),
                    selected: currentPreset == p,
                    onSelected: _busy ? null : (_) => _setPreset(p),
                  ),
                )
                .toList(),
          ),
        ),

        if (_share.isRoom && (_share.shareWith?.isNotEmpty ?? false)) ...[
          const Divider(height: 24),
          ListTile(
            leading: const CenteredLeading(Icon(Icons.chat_bubble_outline)),
            title: const Text('Im Talk-Chat öffnen'),
            onTap: _busy ? null : _openInTalk,
          ),
        ],

        if (_share.isPublicLink) ...[
          const Divider(height: 24),
          if (_share.url != null)
            ListTile(
              leading: const CenteredLeading(Icon(Icons.link_outlined)),
              title: const Text('Öffentlicher Link'),
              subtitle: Text(
                _share.url!,
                maxLines: 1,
                overflow: TextOverflow.ellipsis,
              ),
              trailing: IconButton(
                onPressed: () => copyToClipboard(context, _share.url!),
                tooltip: 'Link kopieren',
                icon: const Icon(Icons.copy_outlined),
              ),
            ),
          ListTile(
            leading: const CenteredLeading(Icon(Icons.event_outlined)),
            title: const Text('Ablaufdatum'),
            subtitle: Text(_share.expiration ?? 'Kein Ablaufdatum'),
            trailing: _share.expiration != null && !caps.expireEnforced
                ? IconButton(
                    icon: const Icon(Icons.clear),
                    tooltip: 'Ablaufdatum entfernen',
                    onPressed: _busy ? null : _clearExpiry,
                  )
                : null,
            onTap: _busy ? null : _pickExpiry,
          ),
          ListTile(
            leading: CenteredLeading(
              Icon(
                _share.hasPassword
                    ? Icons.lock_outline
                    : Icons.lock_open_outlined,
              ),
            ),
            title: Text(
              _share.hasPassword ? 'Passwortgeschützt' : 'Kein Passwort',
            ),
            subtitle: Text(
              caps.passwordEnforced && !_share.hasPassword
                  ? 'Erforderlich – tippen zum Festlegen'
                  : _share.hasPassword
                  ? 'Tippen zum Ändern'
                  : 'Tippen zum Festlegen',
            ),
            trailing: _share.hasPassword && !caps.passwordEnforced
                ? IconButton(
                    icon: const Icon(Icons.delete_outline),
                    tooltip: 'Passwort entfernen',
                    onPressed: _busy ? null : _clearPassword,
                  )
                : null,
            onTap: _busy ? null : _changePassword,
          ),
        ],

        const Divider(height: 24),
        ListTile(
          leading: CenteredLeading(
            Icon(Icons.delete_outline, color: theme.colorScheme.error),
          ),
          title: Text(
            'Freigabe löschen',
            style: TextStyle(color: theme.colorScheme.error),
          ),
          onTap: _busy ? null : _confirmDelete,
        ),
      ],
    );
  }
}
