import 'dart:io';

import 'package:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_context_menu/flutter_context_menu.dart';
import 'package:gap/gap.dart';
import 'package:go_router/go_router.dart';
import 'package:hotkey_manager/hotkey_manager.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:pasteboard/pasteboard.dart';
import 'package:responsive_framework/responsive_framework.dart';
import 'package:styled_widget/styled_widget.dart';
import 'package:surface/controllers/post_write_controller.dart';
import 'package:surface/providers/config.dart';
import 'package:surface/providers/sn_attachment.dart';
import 'package:surface/providers/sn_network.dart';
import 'package:surface/providers/sn_realm.dart';
import 'package:surface/types/attachment.dart';
import 'package:surface/types/post.dart';
import 'package:surface/types/realm.dart';
import 'package:surface/widgets/account/account_image.dart';
import 'package:surface/widgets/attachment/attachment_input.dart';
import 'package:surface/widgets/attachment/attachment_item.dart';
import 'package:surface/widgets/attachment/pending_attachment_alt.dart';
import 'package:surface/widgets/attachment/pending_attachment_boost.dart';
import 'package:surface/widgets/loading_indicator.dart';
import 'package:surface/widgets/markdown_content.dart';
import 'package:surface/widgets/navigation/app_scaffold.dart';
import 'package:surface/widgets/post/post_media_pending_list.dart';
import 'package:surface/widgets/post/post_meta_editor.dart';
import 'package:surface/widgets/dialog.dart';
import 'package:provider/provider.dart';
import 'package:surface/widgets/post/post_poll_editor.dart';
import 'package:uuid/uuid.dart';

const kPostTypes = ['Story', 'Article', 'Question', 'Video'];
const kPostTypeAliases = ['stories', 'articles', 'questions', 'videos'];

class PostEditorExtra {
  final String? text;
  final String? title;
  final String? description;
  final List<PostWriteMedia>? attachments;
  final SnRealm? realm;

  const PostEditorExtra({
    this.text,
    this.title,
    this.description,
    this.attachments,
    this.realm,
  });
}

class PostEditorScreen extends StatefulWidget {
  final String? mode;
  final int? postEditId;
  final int? postReplyId;
  final int? postRepostId;
  final PostEditorExtra? extraProps;

  const PostEditorScreen({
    super.key,
    required this.mode,
    required this.postEditId,
    required this.postReplyId,
    required this.postRepostId,
    this.extraProps,
  });

  @override
  State<PostEditorScreen> createState() => _PostEditorScreenState();
}

class _PostEditorScreenState extends State<PostEditorScreen>
    with SingleTickerProviderStateMixin {
  late final TabController _tabController =
      TabController(length: 4, vsync: this);
  late final PostWriteController _writeController = PostWriteController(
    doLoadFromTemporary: widget.postEditId == null,
  );

  bool _isFetching = false;

  bool get _isLoading => _isFetching || _writeController.isLoading;

  List<SnPublisher>? _publishers;
  List<SnRealm>? _realms;

  Future<void> _fetchPublishers() async {
    setState(() => _isFetching = true);

    try {
      final sn = context.read<SnNetworkProvider>();
      final config = context.read<ConfigProvider>();
      final resp = await sn.client.get('/cgi/co/publishers/me');
      _publishers = List<SnPublisher>.from(
        resp.data?.map((e) => SnPublisher.fromJson(e)) ?? [],
      );
      final beforeId = config.prefs.getInt('int_last_publisher_id');
      _writeController.setPublisher(
          _publishers?.where((ele) => ele.id == beforeId).firstOrNull ??
              _publishers?.firstOrNull);
    } catch (err) {
      if (!mounted) return;
      context.showErrorDialog(err);
    } finally {
      setState(() => _isFetching = false);
    }
  }

  Future<void> _fetchRealms() async {
    final rels = context.read<SnRealmProvider>();
    try {
      _realms = await rels.listAvailableRealms();
    } catch (err) {
      if (!mounted) return;
      context.showErrorDialog(err);
    }
  }

  void _updateMeta() {
    showModalBottomSheet(
      context: context,
      builder: (context) => PostMetaEditor(controller: _writeController),
      useRootNavigator: true,
    );
  }

  final HotKey _pasteHotKey = HotKey(
    key: PhysicalKeyboardKey.keyV,
    modifiers: [
      (!kIsWeb && Platform.isMacOS)
          ? HotKeyModifier.meta
          : HotKeyModifier.control
    ],
    scope: HotKeyScope.inapp,
  );
  final HotKey _saveDraftHotKey = HotKey(
    key: PhysicalKeyboardKey.keyS,
    modifiers: [
      (!kIsWeb && Platform.isMacOS)
          ? HotKeyModifier.meta
          : HotKeyModifier.control
    ],
    scope: HotKeyScope.inapp,
  );

  void _registerHotKey() {
    if (kIsWeb || Platform.isAndroid || Platform.isIOS) return;
    hotKeyManager.register(_pasteHotKey, keyDownHandler: (_) async {
      final imageBytes = await Pasteboard.image;
      if (imageBytes == null) return;
      _writeController.addAttachments([
        PostWriteMedia.fromBytes(
          imageBytes,
          'attachmentPastedImage'.tr(),
          SnMediaType.image,
        ),
      ]);
      setState(() {});
    });
    hotKeyManager.register(_saveDraftHotKey, keyDownHandler: (_) async {
      if (mounted) {
        _writeController.sendPost(context, saveAsDraft: true);
      }
    });
  }

  void _showPublisherPopup() {
    showModalBottomSheet(
      context: context,
      builder: (context) => _PostPublisherPopup(
        controller: _writeController,
        publishers: _publishers,
        onUpdate: () {
          _fetchPublishers();
        },
      ),
    );
  }

  void _showRealmPopup() {
    showModalBottomSheet(
      context: context,
      builder: (context) => _PostRealmPopup(
        controller: _writeController,
        realms: _realms,
        onUpdate: () {
          _fetchRealms();
        },
      ),
    );
  }

  void _showPollEditorDialog() async {
    final poll = await showDialog<dynamic>(
      context: context,
      builder: (context) => PollEditorDialog(
        poll: _writeController.poll,
      ),
    );
    if (poll == null) return;
    if (!mounted) return;

    if (poll == false) {
      _writeController.setPoll(null);
    } else {
      _writeController.setPoll(poll);
    }
  }

  void _showThumbnailEditorDialog() async {
    final attachment = await showDialog<SnAttachment?>(
      context: context,
      builder: (context) => AttachmentInputDialog(
        title: 'postThumbnail'.tr(),
        pool: 'interactive',
        mediaType: SnMediaType.image,
      ),
    );
    if (!context.mounted) return;
    if (attachment == null) return;
    _writeController.setThumbnail(attachment);
  }

  @override
  void dispose() {
    _tabController.dispose();
    _writeController.dispose();
    if (!kIsWeb && !(Platform.isAndroid || Platform.isIOS)) {
      hotKeyManager.unregister(_pasteHotKey);
      hotKeyManager.unregister(_saveDraftHotKey);
    }
    super.dispose();
  }

  @override
  void initState() {
    super.initState();
    _registerHotKey();
    _fetchRealms();
    _fetchPublishers();
    if (widget.mode != null) {
      _writeController.setMode(widget.mode!);
    }
    _tabController.addListener(() {
      if (_tabController.indexIsChanging) {
        _writeController.setMode(kPostTypeAliases[_tabController.index]);
      }
    });
    _writeController.fetchRelatedPost(
      context,
      editing: widget.postEditId,
      replying: widget.postReplyId,
      reposting: widget.postRepostId,
    );
    if (widget.extraProps != null) {
      _writeController.contentController.text = widget.extraProps!.text ?? '';
      _writeController.titleController.text = widget.extraProps!.title ?? '';
      _writeController.descriptionController.text =
          widget.extraProps!.description ?? '';
      _writeController.addAttachments(widget.extraProps!.attachments ?? []);
      _writeController.setRealm(widget.extraProps!.realm);
    }
  }

  @override
  Widget build(BuildContext context) {
    return ListenableBuilder(
      listenable: _writeController,
      builder: (context, _) {
        return AppScaffold(
          appBar: AppBar(
            leading: BackButton(
              onPressed: () {
                Navigator.pop(context);
              },
            ),
            title: Text(
              _writeController.title.isNotEmpty
                  ? _writeController.title
                  : 'untitled'.tr(),
            ),
            actions: [
              IconButton(
                icon: _writeController.editingDraft
                    ? const Icon(Icons.save)
                    : const Icon(Symbols.save_as),
                onPressed: () {
                  _writeController.sendPost(context, saveAsDraft: true).then(
                    (_) {
                      if (!context.mounted) return;
                      context.showSnackbar('postDraftSaved'.tr());
                      HapticFeedback.mediumImpact();
                    },
                  );
                },
              ),
              IconButton(
                icon: const Icon(Symbols.tune),
                onPressed: _writeController.isBusy ? null : _updateMeta,
              ),
              const Gap(8),
            ],
            bottom: _writeController.isNotEmpty || widget.mode != null
                ? null
                : TabBar(
                    controller: _tabController,
                    tabs: [
                      for (final type in kPostTypes)
                        Tab(
                          child: Text(
                            'postType$type'.tr(),
                            style: TextStyle(
                              color: Theme.of(context)
                                  .appBarTheme
                                  .foregroundColor!,
                            ),
                          ),
                        ),
                    ],
                  ),
          ),
          body: Column(
            children: [
              if (_writeController.editingPost != null &&
                  !_writeController.editingDraft)
                Container(
                  padding: const EdgeInsets.only(
                      top: 4, bottom: 4, left: 20, right: 20),
                  decoration: BoxDecoration(
                    border: Border(
                      bottom: BorderSide(
                        color: Theme.of(context).dividerColor,
                        width: 1 / MediaQuery.of(context).devicePixelRatio,
                      ),
                    ),
                  ),
                  child: Row(
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: [
                      const Icon(Icons.edit, size: 16),
                      const Gap(10),
                      Text('postEditingNotice').tr(args: [
                        '@${_writeController.editingPost!.publisher.name}'
                      ]),
                    ],
                  ),
                ),
              if (_writeController.replyingPost != null)
                Container(
                  padding: const EdgeInsets.only(
                      top: 4, bottom: 4, left: 20, right: 20),
                  decoration: BoxDecoration(
                    border: Border(
                      bottom: BorderSide(
                        color: Theme.of(context).dividerColor,
                        width: 1 / MediaQuery.of(context).devicePixelRatio,
                      ),
                    ),
                  ),
                  child: Row(
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: [
                      const Icon(Symbols.reply, size: 16),
                      const Gap(10),
                      Text('@${_writeController.replyingPost!.publisher.name}')
                          .bold(),
                      const Gap(4),
                      Expanded(
                        child: Text(
                          _writeController.replyingPost!.body['content'],
                          maxLines: 1,
                          overflow: TextOverflow.ellipsis,
                        ),
                      ),
                    ],
                  ),
                ),
              if (_writeController.repostingPost != null)
                Container(
                  padding: const EdgeInsets.only(
                      top: 4, bottom: 4, left: 20, right: 20),
                  decoration: BoxDecoration(
                    border: Border(
                      bottom: BorderSide(
                        color: Theme.of(context).dividerColor,
                        width: 1 / MediaQuery.of(context).devicePixelRatio,
                      ),
                    ),
                  ),
                  child: Row(
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: [
                      const Icon(Symbols.forward, size: 16),
                      const Gap(10),
                      Text('@${_writeController.repostingPost!.publisher.name}')
                          .bold(),
                      const Gap(4),
                      Expanded(
                        child: Text(
                          _writeController.repostingPost!.body['content'],
                          maxLines: 1,
                          overflow: TextOverflow.ellipsis,
                        ),
                      ),
                    ],
                  ),
                ),
              Expanded(
                child: Stack(
                  children: [
                    SingleChildScrollView(
                      padding: EdgeInsets.only(bottom: 160),
                      child: switch (_writeController.mode) {
                        'stories' => _PostStoryEditor(
                            controller: _writeController,
                            onTapPublisher: _showPublisherPopup,
                            onTapRealm: _showRealmPopup,
                          ),
                        'articles' => _PostArticleEditor(
                            controller: _writeController,
                            onTapPublisher: _showPublisherPopup,
                            onTapRealm: _showRealmPopup,
                          ),
                        'questions' => _PostQuestionEditor(
                            controller: _writeController,
                            onTapPublisher: _showPublisherPopup,
                            onTapRealm: _showRealmPopup,
                          ),
                        'videos' => _PostVideoEditor(
                            controller: _writeController,
                            onTapPublisher: _showPublisherPopup,
                            onTapRealm: _showRealmPopup,
                          ),
                        _ => const Placeholder(),
                      },
                    ),
                    if (_writeController.attachments.isNotEmpty ||
                        _writeController.thumbnail != null)
                      Positioned(
                        bottom: 0,
                        left: 0,
                        right: 0,
                        child: PostMediaPendingList(
                          attachments: _writeController.attachments,
                          isBusy: _writeController.isBusy,
                          onUpload: (int idx) async {
                            await _writeController.uploadSingleAttachment(
                                context, idx);
                          },
                          onInsertLink: (int idx) async {
                            _writeController.contentController.text +=
                                '\n![](solink://attachments/${_writeController.attachments[idx].attachment!.rid})';
                          },
                          onUpdate:
                              (int idx, PostWriteMedia updatedMedia) async {
                            _writeController.setIsBusy(true);
                            try {
                              _writeController.setAttachmentAt(
                                  idx, updatedMedia);
                            } finally {
                              _writeController.setIsBusy(false);
                            }
                          },
                          onRemove: (int idx) async {
                            _writeController.setIsBusy(true);
                            try {
                              _writeController.removeAttachmentAt(idx);
                            } finally {
                              _writeController.setIsBusy(false);
                            }
                          },
                          onUpdateBusy: (state) =>
                              _writeController.setIsBusy(state),
                        ).padding(bottom: 8),
                      ),
                  ],
                ),
              ),
              Material(
                elevation: 2,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    if (_writeController.isBusy &&
                        _writeController.progress != null)
                      TweenAnimationBuilder<double>(
                        tween: Tween(begin: 0, end: _writeController.progress),
                        duration: Duration(milliseconds: 300),
                        builder: (context, value, _) =>
                            LinearProgressIndicator(value: value, minHeight: 2),
                      )
                    else if (_writeController.isBusy)
                      const LinearProgressIndicator(value: null, minHeight: 2),
                    LoadingIndicator(isActive: _isLoading),
                    const Gap(4),
                    Container(
                      child: _writeController.temporaryRestored
                          ? Container(
                              padding: const EdgeInsets.only(
                                  top: 4, bottom: 4, left: 28, right: 22),
                              decoration: BoxDecoration(
                                border: Border(
                                  bottom: BorderSide(
                                    color: Theme.of(context).dividerColor,
                                    width: 1 /
                                        MediaQuery.of(context).devicePixelRatio,
                                  ),
                                ),
                              ),
                              child: Row(
                                crossAxisAlignment: CrossAxisAlignment.center,
                                children: [
                                  const Icon(Icons.restore, size: 20),
                                  const Gap(8),
                                  Expanded(
                                      child:
                                          Text('postLocalDraftRestored').tr()),
                                  InkWell(
                                    child: Text('dialogDismiss').tr(),
                                    onTap: () {
                                      _writeController.reset();
                                    },
                                  ),
                                ],
                              ))
                          : const SizedBox.shrink(),
                    )
                        .height(_writeController.temporaryRestored ? 32 : 0,
                            animate: true)
                        .animate(const Duration(milliseconds: 300),
                            Curves.fastLinearToSlowEaseIn),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Expanded(
                          child: ScrollConfiguration(
                            behavior: _PostEditorActionScrollBehavior(),
                            child: SingleChildScrollView(
                              scrollDirection: Axis.vertical,
                              child: Row(
                                children: [
                                  AddPostMediaButton(
                                    onAdd: (items) {
                                      setState(() {
                                        _writeController.addAttachments(items);
                                      });
                                    },
                                  ),
                                  if (_writeController.mode == 'stories')
                                    IconButton(
                                      icon: Icon(Symbols.poll,
                                          color: Theme.of(context)
                                              .colorScheme
                                              .primary),
                                      style: ButtonStyle(
                                        backgroundColor:
                                            _writeController.poll == null
                                                ? null
                                                : WidgetStatePropertyAll(
                                                    Theme.of(context)
                                                        .colorScheme
                                                        .surfaceContainer),
                                      ),
                                      onPressed: () {
                                        _showPollEditorDialog();
                                      },
                                    ),
                                  if (_writeController.mode == 'articles')
                                    IconButton(
                                      icon: Icon(Symbols.full_coverage,
                                          color: Theme.of(context)
                                              .colorScheme
                                              .primary),
                                      style: ButtonStyle(
                                        backgroundColor:
                                            _writeController.thumbnail == null
                                                ? null
                                                : WidgetStatePropertyAll(
                                                    Theme.of(context)
                                                        .colorScheme
                                                        .surfaceContainer),
                                      ),
                                      onPressed: () {
                                        if (_writeController.thumbnail !=
                                            null) {
                                          _writeController.setThumbnail(null);
                                          return;
                                        }
                                        _showThumbnailEditorDialog();
                                      },
                                    ),
                                ],
                              ),
                            ),
                          ),
                        ),
                        TextButton.icon(
                          onPressed: (_writeController.isBusy ||
                                  _writeController.publisher == null)
                              ? null
                              : () {
                                  _writeController.sendPost(context).then((_) {
                                    if (!context.mounted) return;
                                    Navigator.pop(context, true);
                                  });
                                },
                          icon: const Icon(Symbols.send),
                          label: Text('postPublish').tr(),
                        ),
                      ],
                    ).padding(horizontal: 16),
                  ],
                ).padding(
                  bottom: MediaQuery.of(context).padding.bottom + 8,
                ),
              ),
            ],
          ),
        );
      },
    );
  }
}

class _PostEditorActionScrollBehavior extends MaterialScrollBehavior {
  @override
  Set<PointerDeviceKind> get dragDevices => {
        PointerDeviceKind.touch,
        PointerDeviceKind.mouse,
      };
}

class _PostPublisherPopup extends StatelessWidget {
  final PostWriteController controller;
  final List<SnPublisher>? publishers;
  final Function onUpdate;

  const _PostPublisherPopup(
      {required this.controller, this.publishers, required this.onUpdate});

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            const Icon(Symbols.face, size: 24),
            const Gap(16),
            Text('accountPublishers',
                    style: Theme.of(context).textTheme.titleLarge)
                .tr(),
          ],
        ).padding(horizontal: 20, top: 16, bottom: 12),
        ListTile(
          leading: const Icon(Symbols.add),
          title: Text('publishersNew').tr(),
          subtitle: Text('publisherNewSubtitle').tr(),
          contentPadding: const EdgeInsets.symmetric(horizontal: 24),
          onTap: () {
            GoRouter.of(context).pushNamed('accountPublisherNew').then((value) {
              if (value == true) {
                onUpdate();
              }
            });
          },
        ),
        const Divider(height: 1),
        Expanded(
          child: ListView.builder(
            itemCount: publishers?.length ?? 0,
            itemBuilder: (context, idx) {
              final publisher = publishers![idx];
              return ListTile(
                title: Text(publisher.nick),
                subtitle: Text('@${publisher.name}'),
                leading: AccountImage(content: publisher.avatar, radius: 18),
                onTap: () {
                  controller.setPublisher(publisher);
                  Navigator.pop(context, true);
                },
              );
            },
          ),
        ),
      ],
    );
  }
}

class _PostRealmPopup extends StatelessWidget {
  final PostWriteController controller;
  final List<SnRealm>? realms;
  final Function onUpdate;

  const _PostRealmPopup(
      {required this.controller, this.realms, required this.onUpdate});

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            const Icon(Symbols.face, size: 24),
            const Gap(16),
            Text('accountRealms', style: Theme.of(context).textTheme.titleLarge)
                .tr(),
          ],
        ).padding(horizontal: 20, top: 16, bottom: 12),
        ListTile(
          leading: const Icon(Symbols.close),
          title: Text('postInGlobal').tr(),
          subtitle: Text('postInGlobalDescription').tr(),
          contentPadding: const EdgeInsets.symmetric(horizontal: 24),
          onTap: () {
            controller.setRealm(null);
            Navigator.pop(context, true);
          },
        ),
        const Divider(height: 1),
        Expanded(
          child: ListView.builder(
            itemCount: realms?.length ?? 0,
            itemBuilder: (context, idx) {
              final realm = realms![idx];
              return ListTile(
                title: Text(realm.name),
                subtitle: Text('@${realm.alias}'),
                leading: AccountImage(content: realm.avatar, radius: 18),
                onTap: () {
                  controller.setRealm(realm);
                  Navigator.pop(context, true);
                },
              );
            },
          ),
        ),
      ],
    );
  }
}

class _PostStoryEditor extends StatelessWidget {
  final PostWriteController controller;
  final Function? onTapPublisher;
  final Function? onTapRealm;

  const _PostStoryEditor(
      {required this.controller, this.onTapPublisher, this.onTapRealm});

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.only(left: 12, right: 12, top: 8),
      constraints: const BoxConstraints(maxWidth: 640),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Column(
            children: [
              Material(
                elevation: 2,
                borderRadius: const BorderRadius.all(Radius.circular(24)),
                child: GestureDetector(
                  onTap: () {
                    onTapPublisher?.call();
                  },
                  child: AccountImage(
                    content: controller.publisher?.avatar,
                  ),
                ),
              ),
              const Gap(11),
              Material(
                elevation: 1,
                borderRadius: const BorderRadius.all(Radius.circular(24)),
                child: GestureDetector(
                  onTap: () {
                    onTapRealm?.call();
                  },
                  child: AccountImage(
                    content: controller.realm?.avatar,
                    fallbackWidget: const Icon(Symbols.globe, size: 20),
                    radius: 14,
                  ),
                ),
              ),
            ],
          ),
          Expanded(
            child: Column(
              children: [
                const Gap(6),
                TextField(
                  controller: controller.titleController,
                  decoration: InputDecoration.collapsed(
                    hintText: 'fieldPostTitle'.tr(),
                    border: InputBorder.none,
                  ),
                  style: Theme.of(context).textTheme.titleLarge,
                  onTapOutside: (_) =>
                      FocusManager.instance.primaryFocus?.unfocus(),
                ).padding(horizontal: 16),
                const Gap(8),
                TextField(
                  controller: controller.contentController,
                  maxLines: null,
                  decoration: InputDecoration(
                    hintText: 'fieldPostContent'.tr(),
                    hintStyle: TextStyle(fontSize: 14),
                    isCollapsed: true,
                    contentPadding: const EdgeInsets.symmetric(
                      horizontal: 16,
                    ),
                    border: InputBorder.none,
                  ),
                  onTapOutside: (_) =>
                      FocusManager.instance.primaryFocus?.unfocus(),
                  contentInsertionConfiguration:
                      controller.contentInsertionConfiguration,
                ),
              ],
            ),
          ),
        ],
      ).padding(bottom: 8),
    );
  }
}

class _PostArticleEditor extends StatelessWidget {
  final PostWriteController controller;
  final Function? onTapPublisher;
  final Function? onTapRealm;

  const _PostArticleEditor(
      {required this.controller, this.onTapPublisher, this.onTapRealm});

  @override
  Widget build(BuildContext context) {
    final editorWidgets = <Widget>[
      Material(
        color: Theme.of(context).colorScheme.surfaceContainerHigh,
        child: InkWell(
          child: Row(
            children: [
              AccountImage(content: controller.publisher?.avatar, radius: 20),
              const Gap(8),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(controller.publisher?.nick ?? 'loading'.tr()).bold(),
                    Text('@${controller.publisher?.name}'),
                  ],
                ),
              ),
              Material(
                elevation: 1,
                borderRadius: const BorderRadius.all(Radius.circular(24)),
                child: GestureDetector(
                  onTap: () {
                    onTapRealm?.call();
                  },
                  child: AccountImage(
                    content: controller.realm?.avatar,
                    fallbackWidget: const Icon(Symbols.globe, size: 20),
                    radius: 14,
                  ),
                ),
              ),
              const Gap(8),
            ],
          ).padding(horizontal: 12, vertical: 8),
          onTap: () {
            onTapPublisher?.call();
          },
        ),
      ),
      const Gap(16),
      TextField(
        controller: controller.titleController,
        decoration: InputDecoration.collapsed(
          hintText: 'fieldPostTitle'.tr(),
          border: InputBorder.none,
        ),
        style: Theme.of(context).textTheme.titleLarge,
        onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
      ).padding(horizontal: 16),
      const Gap(8),
      TextField(
        controller: controller.descriptionController,
        decoration: InputDecoration.collapsed(
          hintText: 'fieldPostDescription'.tr(),
          border: InputBorder.none,
        ),
        maxLines: null,
        keyboardType: TextInputType.multiline,
        style: Theme.of(context).textTheme.bodyLarge,
        onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
        contentInsertionConfiguration: controller.contentInsertionConfiguration,
      ).padding(horizontal: 16),
      if (controller.thumbnail != null)
        Container(
          margin: const EdgeInsets.only(left: 12, right: 12, top: 8, bottom: 4),
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(8),
            border: Border.all(color: Theme.of(context).dividerColor),
          ),
          child: ClipRRect(
            borderRadius: const BorderRadius.all(Radius.circular(8)),
            child: AspectRatio(
              aspectRatio: 16 / 9,
              child: AttachmentItem(
                data: controller.thumbnail!.attachment!,
                heroTag: "post-editor-thumbnail-preview",
              ),
            ),
          ),
        ),
    ];

    if (ResponsiveBreakpoints.of(context).largerThan(MOBILE)) {
      return Container(
        constraints: const BoxConstraints(maxWidth: 640 * 2 + 8),
        child: Column(
          children: [
            ...editorWidgets,
            Row(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Expanded(
                  child: TextField(
                    controller: controller.contentController,
                    maxLines: null,
                    decoration: InputDecoration(
                      hintText: 'fieldPostContent'.tr(),
                      hintStyle: TextStyle(fontSize: 14),
                      isCollapsed: true,
                      contentPadding: const EdgeInsets.symmetric(
                        horizontal: 16,
                      ),
                      border: InputBorder.none,
                    ),
                    onTapOutside: (_) =>
                        FocusManager.instance.primaryFocus?.unfocus(),
                    contentInsertionConfiguration:
                        controller.contentInsertionConfiguration,
                  ),
                ),
                const Gap(8),
                Expanded(
                  child: MarkdownTextContent(
                    content: controller.contentController.text,
                  ).padding(horizontal: 24),
                ),
              ],
            ),
          ],
        ),
      );
    }

    return Column(
      children: [
        ...editorWidgets,
        Container(
          padding: const EdgeInsets.only(top: 8),
          constraints: const BoxConstraints(maxWidth: 640),
          child: TextField(
            controller: controller.contentController,
            maxLines: null,
            decoration: InputDecoration(
              hintText: 'fieldPostContent'.tr(),
              hintStyle: TextStyle(fontSize: 14),
              isCollapsed: true,
              contentPadding: const EdgeInsets.symmetric(
                horizontal: 16,
              ),
              border: InputBorder.none,
            ),
            onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
            contentInsertionConfiguration:
                controller.contentInsertionConfiguration,
          ),
        ),
      ],
    );
  }
}

class _PostQuestionEditor extends StatelessWidget {
  final PostWriteController controller;
  final Function? onTapPublisher;
  final Function? onTapRealm;

  const _PostQuestionEditor(
      {required this.controller, this.onTapPublisher, this.onTapRealm});

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.only(left: 12, right: 12, top: 8),
      constraints: const BoxConstraints(maxWidth: 640),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Column(
            children: [
              Material(
                elevation: 2,
                borderRadius: const BorderRadius.all(Radius.circular(24)),
                child: GestureDetector(
                  onTap: () {
                    onTapPublisher?.call();
                  },
                  child: AccountImage(
                    content: controller.publisher?.avatar,
                  ),
                ),
              ),
              const Gap(11),
              Material(
                elevation: 1,
                borderRadius: const BorderRadius.all(Radius.circular(24)),
                child: GestureDetector(
                  onTap: () {
                    onTapRealm?.call();
                  },
                  child: AccountImage(
                    content: controller.realm?.avatar,
                    fallbackWidget: const Icon(Symbols.globe, size: 20),
                    radius: 14,
                  ),
                ),
              ),
            ],
          ),
          Expanded(
            child: Column(
              children: [
                const Gap(6),
                TextField(
                  controller: controller.titleController,
                  decoration: InputDecoration.collapsed(
                    hintText: 'fieldPostTitle'.tr(),
                    border: InputBorder.none,
                  ),
                  style: Theme.of(context).textTheme.titleLarge,
                  onTapOutside: (_) =>
                      FocusManager.instance.primaryFocus?.unfocus(),
                ).padding(horizontal: 16),
                const Gap(8),
                TextField(
                  controller: controller.rewardController,
                  decoration: InputDecoration(
                    hintText: 'fieldPostQuestionReward'.tr(),
                    suffixText: 'walletCurrencyShort'.tr(),
                    border: InputBorder.none,
                    isCollapsed: true,
                  ),
                  onTapOutside: (_) =>
                      FocusManager.instance.primaryFocus?.unfocus(),
                ).padding(horizontal: 16),
                const Gap(8),
                TextField(
                  controller: controller.contentController,
                  maxLines: null,
                  decoration: InputDecoration(
                    hintText: 'fieldPostContent'.tr(),
                    hintStyle: TextStyle(fontSize: 14),
                    isCollapsed: true,
                    contentPadding: const EdgeInsets.symmetric(
                      horizontal: 16,
                    ),
                    border: InputBorder.none,
                  ),
                  onTapOutside: (_) =>
                      FocusManager.instance.primaryFocus?.unfocus(),
                  contentInsertionConfiguration:
                      controller.contentInsertionConfiguration,
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

class _PostVideoEditor extends StatelessWidget {
  final PostWriteController controller;
  final Function? onTapPublisher;
  final Function? onTapRealm;

  const _PostVideoEditor(
      {required this.controller, this.onTapPublisher, this.onTapRealm});

  void _selectVideo(BuildContext context) async {
    final video = await showDialog<SnAttachment?>(
      context: context,
      builder: (context) => AttachmentInputDialog(
        title: 'postVideoUpload'.tr(),
        pool: 'interactive',
        mediaType: SnMediaType.video,
      ),
    );
    if (!context.mounted) return;
    if (video == null) return;
    controller.setVideoAttachment(video);
  }

  void _setAlt(BuildContext context) async {
    if (controller.videoAttachment == null) return;

    final result = await showDialog<SnAttachment?>(
      context: context,
      builder: (context) => PendingAttachmentAltDialog(
          media: PostWriteMedia(controller.videoAttachment)),
    );
    if (result == null) return;

    controller.setVideoAttachment(result);
  }

  Future<void> _createBoost(BuildContext context) async {
    if (controller.videoAttachment == null) return;

    final result = await showDialog<SnAttachmentBoost?>(
      context: context,
      builder: (context) => PendingAttachmentBoostDialog(
          media: PostWriteMedia(controller.videoAttachment)),
    );
    if (result == null) return;

    final newAttach = controller.videoAttachment!.copyWith(
      boosts: [...controller.videoAttachment!.boosts, result],
    );

    controller.setVideoAttachment(newAttach);
  }

  void _setThumbnail(BuildContext context) async {
    if (controller.videoAttachment == null) return;

    final thumbnail = await showDialog<SnAttachment?>(
      context: context,
      builder: (context) => AttachmentInputDialog(
        title: 'attachmentSetThumbnail'.tr(),
        pool: 'interactive',
        analyzeNow: true,
      ),
    );
    if (thumbnail == null) return;
    if (!context.mounted) return;

    try {
      final attach = context.read<SnAttachmentProvider>();
      final newAttach = await attach.updateOne(
        controller.videoAttachment!,
        thumbnailId: thumbnail.id,
      );
      controller.setVideoAttachment(newAttach);
    } catch (err) {
      if (!context.mounted) return;
      context.showErrorDialog(err);
    }
  }

  Future<void> _deleteAttachment(BuildContext context) async {
    if (controller.videoAttachment == null) return;

    try {
      final sn = context.read<SnNetworkProvider>();
      await sn.client
          .delete('/cgi/uc/attachments/${controller.videoAttachment!.id}');
      controller.setVideoAttachment(null);
    } catch (err) {
      if (!context.mounted) return;
      context.showErrorDialog(err);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.only(left: 12, right: 12, top: 8),
      constraints: const BoxConstraints(maxWidth: 640),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Column(
            children: [
              Material(
                elevation: 2,
                borderRadius: const BorderRadius.all(Radius.circular(24)),
                child: GestureDetector(
                  onTap: () {
                    onTapPublisher?.call();
                  },
                  child: AccountImage(
                    content: controller.publisher?.avatar,
                  ),
                ),
              ),
              const Gap(11),
              Material(
                elevation: 1,
                borderRadius: const BorderRadius.all(Radius.circular(24)),
                child: GestureDetector(
                  onTap: () {
                    onTapRealm?.call();
                  },
                  child: AccountImage(
                    content: controller.realm?.avatar,
                    fallbackWidget: const Icon(Symbols.globe, size: 20),
                    radius: 14,
                  ),
                ),
              ),
            ],
          ),
          Expanded(
            child: Column(
              children: [
                const Gap(6),
                TextField(
                  controller: controller.titleController,
                  decoration: InputDecoration.collapsed(
                    hintText: 'fieldPostTitle'.tr(),
                    border: InputBorder.none,
                  ),
                  style: Theme.of(context).textTheme.titleLarge,
                  onTapOutside: (_) =>
                      FocusManager.instance.primaryFocus?.unfocus(),
                ).padding(horizontal: 16),
                const Gap(8),
                TextField(
                  controller: controller.descriptionController,
                  decoration: InputDecoration.collapsed(
                    hintText: 'fieldPostDescription'.tr(),
                    border: InputBorder.none,
                  ),
                  maxLines: null,
                  keyboardType: TextInputType.multiline,
                  style: Theme.of(context).textTheme.bodyLarge,
                  onTapOutside: (_) =>
                      FocusManager.instance.primaryFocus?.unfocus(),
                ).padding(horizontal: 16),
                const Gap(12),
                Container(
                  margin: const EdgeInsets.only(left: 16, right: 16),
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(16),
                    border: Border.all(color: Theme.of(context).dividerColor),
                  ),
                  child: ContextMenuRegion(
                    contextMenu: ContextMenu(
                      entries: [
                        MenuItem(
                          label: 'attachmentSetAlt'.tr(),
                          icon: Symbols.description,
                          onSelected: () {
                            _setAlt(context);
                          },
                        ),
                        MenuItem(
                          label: 'attachmentBoost'.tr(),
                          icon: Symbols.bolt,
                          onSelected: () {
                            _createBoost(context);
                          },
                        ),
                        MenuItem(
                          label: 'attachmentSetThumbnail'.tr(),
                          icon: Symbols.image,
                          onSelected: () {
                            _setThumbnail(context);
                          },
                        ),
                        MenuItem(
                          label: 'attachmentCopyRandomId'.tr(),
                          icon: Symbols.content_copy,
                          onSelected: () {
                            Clipboard.setData(ClipboardData(
                                text: controller.videoAttachment!.rid));
                          },
                        ),
                        MenuItem(
                          label: 'delete'.tr(),
                          icon: Symbols.delete,
                          onSelected: () => _deleteAttachment(context),
                        ),
                        MenuItem(
                          label: 'unlink'.tr(),
                          icon: Symbols.link_off,
                          onSelected: () {
                            controller.setVideoAttachment(null);
                          },
                        ),
                      ],
                    ),
                    child: InkWell(
                      borderRadius: BorderRadius.circular(16),
                      onTap: controller.videoAttachment == null
                          ? () => _selectVideo(context)
                          : null,
                      child: AspectRatio(
                        aspectRatio: 16 / 9,
                        child: controller.videoAttachment == null
                            ? Center(
                                child: Row(
                                  mainAxisSize: MainAxisSize.min,
                                  crossAxisAlignment: CrossAxisAlignment.center,
                                  mainAxisAlignment: MainAxisAlignment.center,
                                  children: [
                                    const Icon(Icons.add),
                                    const Gap(4),
                                    Text('postVideoUpload'.tr()),
                                  ],
                                ),
                              )
                            : ClipRRect(
                                borderRadius: BorderRadius.circular(16),
                                child: AttachmentItem(
                                  data: controller.videoAttachment!,
                                  heroTag: const Uuid().v4(),
                                ),
                              ),
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}