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

import '../../../../api/marianumcloud/webdav/queries/list_files/cacheable_file.dart';
import '../../../../api/marianumcloud/webdav/webdav_api.dart';
import '../../../../extensions/date_time.dart';
import '../../../../routing/app_routes.dart';
import '../../../../share_intent/remote_file_ref.dart';
import '../../../../state/app/modules/nextcloud_capabilities/bloc/nextcloud_capabilities_cubit.dart';
import '../../../../utils/downloads/download_job.dart';
import '../../../../utils/file_clipboard.dart';
import '../../../../utils/haptics.dart';
import '../../../../widget/centered_leading.dart';
import '../../../../widget/confirm_dialog.dart';
import '../../../../widget/demo_restricted.dart';
import '../../../../widget/details_bottom_sheet.dart';
import '../../../../widget/downloads/download_trigger.dart';
import '../../../../widget/prompt_dialog.dart';
import '../../talk/widgets/highlighted_linkify.dart';
import '../sharing/share_sheet.dart';
import 'file_details_sheet.dart';
import 'file_leading.dart';

class FileElement extends StatefulWidget {
  final CacheableFile file;
  final List<String> path;
  final void Function() refetch;

  /// When non-null, occurrences of this string in the file name are visually
  /// highlighted in the tile title. Used by the Files search delegate.
  final String? highlight;

  const FileElement(
    this.file,
    this.path,
    this.refetch, {
    this.highlight,
    super.key,
  });

  @override
  State<FileElement> createState() => _FileElementState();
}

class _FileElementState extends State<FileElement>
    with DownloadTrigger<FileElement> {
  @override
  String? get downloadRemotePath =>
      widget.file.isDirectory ? null : widget.file.path;

  @override
  void initState() {
    super.initState();
    initDownloadTrigger();
  }

  @override
  void didUpdateWidget(covariant FileElement oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.file.path != widget.file.path) refreshDownloadTrigger();
  }

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

  Widget? _subtitle() {
    final status = downloadJob?.status.value;
    if (status is DownloadInProgress) {
      return Row(
        children: [
          Container(
            margin: const EdgeInsets.only(right: 10),
            child: const Text('Download:'),
          ),
          Expanded(child: LinearProgressIndicator(value: status.percent / 100)),
          Container(
            margin: const EdgeInsets.only(left: 10),
            child: Text('${status.percent.round()}%'),
          ),
        ],
      );
    }
    final modified = widget.file.modifiedAt;
    final size = widget.file.size;
    if (widget.file.isDirectory) {
      if (modified == null) return null;
      return Text('geändert ${modified.formatRelative()}');
    }
    if (size == null && modified == null) return null;
    if (size == null) return Text(modified!.formatRelative());
    if (modified == null) return Text(filesize(size));
    return Text('${filesize(size)}, ${modified.formatRelative()}');
  }

  void _onTap() {
    if (widget.file.isDirectory) {
      AppRoutes.openFolder(
        context,
        widget.path.toList()..add(widget.file.name),
      );
      return;
    }
    if (guardDemoAction(context)) return;
    if (isDownloading) {
      confirmCancelDownload();
      return;
    }
    startDownload(
      name: widget.file.name,
      remoteFile: RemoteFileRef.fromCacheable(widget.file),
    );
  }

  // All paths here are relative to the WebDAV root (matching CacheableFile.path).
  // Root parent is the empty string ''. Folders end with '/'.
  String _parentPathOf(String path) {
    final stripped = path.replaceAll(RegExp(r'^/+|/+$'), '');
    if (!stripped.contains('/')) return '';
    final parts = stripped.split('/')..removeLast();
    return parts.isEmpty ? '' : '${parts.join('/')}/';
  }

  String _joinPath(String folder, String name, {required bool isDirectory}) =>
      isDirectory ? '$folder$name/' : '$folder$name';

  void _rename() {
    if (guardDemoAction(context)) return;
    showPromptDialog(
      context,
      title: 'Umbenennen',
      label: 'Neuer Name',
      confirmButton: 'Umbenennen',
      initialValue: widget.file.name,
      onConfirm: (newName) async {
        if (newName.isEmpty || newName == widget.file.name) return;
        final parent = _parentPathOf(widget.file.path);
        final destination = _joinPath(
          parent,
          newName,
          isDirectory: widget.file.isDirectory,
        );
        final webdav = await WebdavApi.webdav;
        await webdav.move(
          PathUri.parse(widget.file.path),
          PathUri.parse(destination),
        );
        widget.refetch();
      },
    );
  }

  void _putOnClipboard({required bool copy}) {
    if (guardDemoAction(context)) return;
    if (copy) {
      FileClipboard.instance.copy([widget.file]);
    } else {
      FileClipboard.instance.cut([widget.file]);
    }
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text(
          '"${widget.file.name}" zum ${copy ? "Kopieren" : "Verschieben"} bereitgelegt',
        ),
        duration: const Duration(seconds: 2),
      ),
    );
  }

  void _delete() {
    if (guardDemoAction(context)) return;
    ConfirmDialog(
      title: 'Element löschen?',
      content: 'Das Element wird unwiederruflich gelöscht.',
      confirmButton: 'Löschen',
      onConfirmAsync: () async {
        final webdav = await WebdavApi.webdav;
        await webdav.delete(PathUri.parse(widget.file.path));
        widget.refetch();
      },
    ).asDialog(context);
  }

  void _showActionSheet() {
    Haptics.longPress();
    showDetailsBottomSheet(
      context,
      children: (sheetCtx) => [
        ListTile(
          leading: const CenteredLeading(Icon(Icons.info_outline)),
          title: const Text('Info'),
          onTap: () {
            Navigator.of(sheetCtx).pop();
            showFileDetailsSheet(context, widget.file);
          },
        ),
        ListTile(
          leading: const CenteredLeading(Icon(Icons.drive_file_rename_outline)),
          title: const Text('Umbenennen'),
          onTap: () {
            Navigator.of(sheetCtx).pop();
            _rename();
          },
        ),
        ListTile(
          leading: const CenteredLeading(Icon(Icons.drive_file_move_outline)),
          title: const Text('Verschieben'),
          onTap: () {
            Navigator.of(sheetCtx).pop();
            _putOnClipboard(copy: false);
          },
        ),
        ListTile(
          leading: const CenteredLeading(Icon(Icons.copy_outlined)),
          title: const Text('Kopieren'),
          onTap: () {
            Navigator.of(sheetCtx).pop();
            _putOnClipboard(copy: true);
          },
        ),
        if (!widget.file.isDirectory)
          ListTile(
            leading: const CenteredLeading(Icon(Icons.chat_bubble_outline)),
            title: const Text('Im Talk-Chat versenden'),
            onTap: () {
              Navigator.of(sheetCtx).pop();
              if (guardDemoAction(context)) return;
              AppRoutes.openInternalShareToChat(
                context,
                RemoteFileRef.fromCacheable(widget.file),
              );
            },
          ),
        if (context.read<NextcloudCapabilitiesCubit>().canShareAtAll)
          ListTile(
            leading: const CenteredLeading(Icon(Icons.person_add_outlined)),
            title: const Text('Freigeben'),
            onTap: () {
              Navigator.of(sheetCtx).pop();
              showShareSheet(context, widget.file);
            },
          ),
        ListTile(
          leading: CenteredLeading(
            Icon(
              Icons.delete_outline,
              color: Theme.of(sheetCtx).colorScheme.error,
            ),
          ),
          title: Text(
            'Löschen',
            style: TextStyle(color: Theme.of(sheetCtx).colorScheme.error),
          ),
          onTap: () {
            Navigator.of(sheetCtx).pop();
            _delete();
          },
        ),
      ],
    );
  }

  Widget _title(BuildContext context) {
    final base =
        Theme.of(context).textTheme.bodyLarge ??
        DefaultTextStyle.of(context).style;
    if (widget.highlight == null || widget.highlight!.trim().isEmpty) {
      return Text(
        widget.file.name,
        maxLines: 2,
        overflow: TextOverflow.ellipsis,
      );
    }
    return Text.rich(
      TextSpan(
        children: buildHighlightedSpans(
          text: widget.file.name,
          query: widget.highlight,
          baseStyle: base,
        ),
      ),
      maxLines: 2,
      overflow: TextOverflow.ellipsis,
    );
  }

  @override
  Widget build(BuildContext context) => ListTile(
    leading: CenteredLeading(FileLeading(file: widget.file)),
    title: _title(context),
    subtitle: _subtitle(),
    trailing: Icon(widget.file.isDirectory ? Icons.arrow_right : null),
    onTap: _onTap,
    onLongPress: _showActionSheet,
  );
}
