import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:pixes/appdata.dart';
import 'package:pixes/components/batch_download.dart';
import 'package:pixes/components/grid.dart';
import 'package:pixes/components/loading.dart';
import 'package:pixes/components/md.dart';
import 'package:pixes/components/novel.dart';
import 'package:pixes/components/segmented_button.dart';
import 'package:pixes/components/user_preview.dart';
import 'package:pixes/foundation/app.dart';
import 'package:pixes/foundation/image_provider.dart';
import 'package:pixes/network/network.dart';
import 'package:pixes/pages/following_users_page.dart';
import 'package:pixes/utils/block.dart';
import 'package:pixes/utils/translation.dart';
import 'package:url_launcher/url_launcher_string.dart';

import '../components/illust_widget.dart';
import 'illust_page.dart';

class UserInfoPage extends StatefulWidget {
  const UserInfoPage(this.id, {super.key});

  final String id;

  static Map<String, UpdateFollowCallback> followCallbacks = {};

  @override
  State<UserInfoPage> createState() => _UserInfoPageState();
}

class _UserInfoPageState extends LoadingState<UserInfoPage, UserDetails> {
  @override
  void initState() {
    UserInfoPage.followCallbacks[widget.id] = (v) {
      if (data == null) return;
      setState(() {
        data!.isFollowed = v;
      });
    };
    super.initState();
  }

  @override
  void dispose() {
    UserInfoPage.followCallbacks.remove(widget.id);
    super.dispose();
  }

  int page = 0;

  @override
  Widget buildContent(BuildContext context, UserDetails data) {
    return ScaffoldPage(
      content: CustomScrollView(
        slivers: [
          buildUser(),
          SliverToBoxAdapter(
            child: buildHeader("Related users".tl),
          ),
          _RelatedUsers(widget.id),
          buildInformation(),
          buildArtworkHeader(),
          if (page == 4)
            _UserNovels(widget.id)
          else
            _UserArtworks(
              data.id.toString(),
              page,
              key: ValueKey(data.id + page),
            ),
          SliverPadding(
              padding: EdgeInsets.only(bottom: context.padding.bottom)),
        ],
      ),
    );
  }

  bool isFollowing = false;

  void follow() async {
    if (isFollowing) return;
    String type = "";
    if (!data!.isFollowed) {
      await flyoutController.showFlyout(
          navigatorKey: App.rootNavigatorKey.currentState,
          builder: (context) => MenuFlyout(
                items: [
                  MenuFlyoutItem(
                      text: Text("Public".tl),
                      onPressed: () => type = "public"),
                  MenuFlyoutItem(
                      text: Text("Private".tl),
                      onPressed: () => type = "private"),
                ],
              ));
    }
    if (type.isEmpty && !data!.isFollowed) {
      return;
    }
    setState(() {
      isFollowing = true;
    });
    var method = data!.isFollowed ? "delete" : "add";
    var res = await Network().follow(data!.id.toString(), method, type);
    if (res.error) {
      if (mounted) {
        context.showToast(message: "Network Error");
      }
    } else {
      data!.isFollowed = !data!.isFollowed;
      UserPreviewWidget.followCallbacks[data!.id.toString()]
          ?.call(data!.isFollowed);
      IllustPage.updateFollow(data!.id.toString(), data!.isFollowed);
    }
    setState(() {
      isFollowing = false;
    });
  }

  var flyoutController = FlyoutController();

  Widget buildUser() {
    return SliverToBoxAdapter(
      child: Column(
        children: [
          Container(
            width: 64,
            height: 64,
            decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(64),
                border: Border.all(
                    color: ColorScheme.of(context).outlineVariant, width: 0.6)),
            child: ClipRRect(
              borderRadius: BorderRadius.circular(64),
              child: Image(
                image: CachedImageProvider(data!.avatar),
                width: 64,
                height: 64,
                fit: BoxFit.cover,
              ),
            ),
          ),
          const SizedBox(height: 8),
          Text(data!.name,
              style:
                  const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
          const SizedBox(height: 4),
          Text.rich(
            TextSpan(
              children: [
                TextSpan(text: 'Follows: '.tl),
                TextSpan(
                    text: '${data!.totalFollowUsers}',
                    recognizer: TapGestureRecognizer()
                      ..onTap = (() =>
                          context.to(() => FollowingUsersPage(widget.id))),
                    style: TextStyle(
                        fontWeight: FontWeight.bold,
                        color: FluentTheme.of(context).accentColor)),
              ],
            ),
            style: const TextStyle(fontSize: 14),
          ),
          if (widget.id != appdata.account?.user.id)
            const SizedBox(
              height: 8,
            ),
          if (widget.id != appdata.account?.user.id)
            if (isFollowing)
              Button(
                  onPressed: follow,
                  child: const SizedBox(
                    width: 42,
                    height: 24,
                    child: Center(
                      child: SizedBox.square(
                        dimension: 18,
                        child: ProgressRing(
                          strokeWidth: 2,
                        ),
                      ),
                    ),
                  ))
            else if (!data!.isFollowed)
              FlyoutTarget(
                  controller: flyoutController,
                  child: Button(onPressed: follow, child: Text("Follow".tl)))
            else
              Button(
                onPressed: follow,
                child: Text(
                  "Unfollow".tl,
                  style: TextStyle(color: ColorScheme.of(context).error),
                ),
              ),
        ],
      ),
    );
  }

  Widget buildHeader(String title, {Widget? action}) {
    return SizedBox(
            width: double.infinity,
            height: 38,
            child: Row(
              children: [
                Text(
                  title,
                  style: const TextStyle(fontWeight: FontWeight.w600),
                ).toAlign(Alignment.centerLeft),
                const Spacer(),
                if (action != null) action.toAlign(Alignment.centerRight)
              ],
            ).paddingHorizontal(16))
        .paddingTop(8);
  }

  Widget buildArtworkHeader() {
    return SliverToBoxAdapter(
      child: SizedBox(
              width: double.infinity,
              height: 38,
              child: Row(
                children: [
                  SegmentedButton<int>(
                    options: [
                      SegmentedButtonOption(0, "Artworks".tl),
                      SegmentedButtonOption(1, "Illustrations".tl),
                      SegmentedButtonOption(2, "Mangas".tl),
                      SegmentedButtonOption(3, "Bookmarks".tl),
                      SegmentedButtonOption(4, "Novels".tl),
                    ],
                    value: page,
                    onPressed: (value) {
                      setState(() {
                        page = value;
                      });
                    },
                  ),
                  const Spacer(),
                  if (page != 4)
                    BatchDownloadButton(
                      request: () {
                        switch (page) {
                          case 0:
                            return Network()
                                .getUserIllusts(data!.id.toString(), null);
                          case 1:
                            return Network()
                                .getUserIllusts(data!.id.toString(), "illust");
                          case 2:
                            return Network()
                                .getUserIllusts(data!.id.toString(), "manga");
                          case 3:
                            return Network()
                                .getUserBookmarks(data!.id.toString());
                        }
                        throw "Invalid page";
                      },
                    ),
                ],
              ).paddingHorizontal(16))
          .paddingTop(12),
    );
  }

  Widget buildInformation() {
    Widget buildItem(
        {IconData? icon,
        required String title,
        required String? content,
        Widget? trailing}) {
      if (content == null || content.isEmpty) {
        return const SizedBox.shrink();
      }
      return Card(
        margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 2),
        padding: EdgeInsets.zero,
        child: ListTile(
          title: Row(
            children: [
              Icon(icon, size: 20),
              const SizedBox(width: 8),
              Text(title)
            ],
          ),
          subtitle: SelectableText(content).paddingLeft(icon == null ? 0 : 28),
          trailing: trailing,
        ),
      );
    }

    return SliverToBoxAdapter(
      child: Column(
        children: [
          buildHeader("Information".tl),
          buildItem(
              icon: MdIcons.comment_outlined,
              title: "Introduction".tl,
              content: data!.comment),
          buildItem(
              icon: MdIcons.cake_outlined,
              title: "Birthday".tl,
              content: data!.birth),
          buildItem(
              icon: MdIcons.location_city_outlined,
              title: "Region",
              content: data!.region),
          buildItem(
              icon: MdIcons.work_outline, title: "Job".tl, content: data!.job),
          buildItem(
              icon: MdIcons.person_2_outlined,
              title: "Gender".tl,
              content: data!.gender),
          buildHeader("Social Network".tl),
          buildItem(
              title: "Webpage",
              content: data!.webpage,
              trailing: IconButton(
                  icon: const Icon(MdIcons.open_in_new, size: 18),
                  onPressed: () => launchUrlString(data!.twitterUrl!))),
          buildItem(
              title: "Twitter",
              content: data!.twitterUrl,
              trailing: IconButton(
                  icon: const Icon(MdIcons.open_in_new, size: 18),
                  onPressed: () => launchUrlString(data!.twitterUrl!))),
          buildItem(
              title: "pawoo",
              content: data!.pawooUrl,
              trailing: IconButton(
                  icon: const Icon(
                    MdIcons.open_in_new,
                    size: 18,
                  ),
                  onPressed: () => launchUrlString(data!.pawooUrl!))),
        ],
      ),
    );
  }

  @override
  Future<Res<UserDetails>> loadData() {
    return Network().getUserDetails(widget.id);
  }
}

class _UserArtworks extends StatefulWidget {
  const _UserArtworks(this.uid, this.type, {super.key});

  final String uid;

  final int type;

  @override
  State<_UserArtworks> createState() => _UserArtworksState();
}

class _UserArtworksState extends MultiPageLoadingState<_UserArtworks, Illust> {
  @override
  Widget buildLoading(BuildContext context) {
    return const SliverToBoxAdapter(
      child: SizedBox(
        child: Center(
          child: ProgressRing(),
        ),
      ),
    );
  }

  @override
  Widget buildError(context, error) {
    return SliverToBoxAdapter(
      child: SizedBox(
        child: Center(
          child: Row(
            children: [
              const Icon(FluentIcons.info),
              const SizedBox(
                width: 4,
              ),
              Text(error)
            ],
          ),
        ),
      ),
    );
  }

  @override
  Widget buildContent(BuildContext context, List<Illust> data) {
    checkIllusts(data);
    return SliverMasonryGrid(
      gridDelegate: const SliverSimpleGridDelegateWithMaxCrossAxisExtent(
        maxCrossAxisExtent: 240,
      ),
      delegate: SliverChildBuilderDelegate(
        (context, index) {
          if (index == data.length - 1) {
            nextPage();
          }
          return IllustWidget(data[index], onTap: () {
            context.to(() => IllustGalleryPage(
                illusts: data, initialPage: index, nextUrl: nextUrl));
          });
        },
        childCount: data.length,
      ),
    ).sliverPaddingHorizontal(8);
  }

  String? nextUrl;

  @override
  Future<Res<List<Illust>>> loadData(page) async {
    if (nextUrl == "end") {
      return Res.error("No more data");
    }
    var res = nextUrl == null
        ? (widget.type != 3
            ? await Network().getUserIllusts(
                widget.uid, [null, "illust", "manga"][widget.type])
            : await Network().getUserBookmarks(widget.uid))
        : await Network().getIllustsWithNextUrl(nextUrl!);
    if (!res.error) {
      nextUrl = res.subData;
      nextUrl ??= "end";
    }
    return res;
  }
}

class _UserNovels extends StatefulWidget {
  const _UserNovels(this.uid);

  final String uid;

  @override
  State<_UserNovels> createState() => _UserNovelsState();
}

class _UserNovelsState extends MultiPageLoadingState<_UserNovels, Novel> {
  @override
  Widget buildLoading(BuildContext context) {
    return const SliverToBoxAdapter(
      child: SizedBox(
        child: Center(
          child: ProgressRing(),
        ),
      ),
    );
  }

  @override
  Widget buildError(context, error) {
    return SliverToBoxAdapter(
      child: SizedBox(
        child: Center(
          child: Row(
            children: [
              const Icon(FluentIcons.info),
              const SizedBox(
                width: 4,
              ),
              Text(error)
            ],
          ),
        ),
      ),
    );
  }

  @override
  Widget buildContent(BuildContext context, List<Novel> data) {
    return SliverGridViewWithFixedItemHeight(
      itemHeight: 164,
      minCrossAxisExtent: 400,
      delegate: SliverChildBuilderDelegate(
        (context, index) {
          if (index == data.length - 1) {
            nextPage();
          }
          return NovelWidget(data[index]);
        },
        childCount: data.length,
      ),
    ).sliverPaddingHorizontal(8);
  }

  String? nextUrl;

  @override
  Future<Res<List<Novel>>> loadData(page) async {
    if (nextUrl == "end") {
      return Res.error("No more data");
    }
    var res = nextUrl == null
        ? await Network().getUserNovels(widget.uid)
        : await Network().getNovelsWithNextUrl(nextUrl!);
    if (!res.error) {
      nextUrl = res.subData;
      nextUrl ??= "end";
    }
    return res;
  }
}

class _RelatedUsers extends StatefulWidget {
  const _RelatedUsers(this.uid);

  final String uid;

  @override
  State<_RelatedUsers> createState() => _RelatedUsersState();
}

class _RelatedUsersState
    extends LoadingState<_RelatedUsers, List<UserPreview>> {
  @override
  Widget buildFrame(BuildContext context, Widget child) {
    return SliverToBoxAdapter(
      child: SizedBox(
        height: 146,
        width: double.infinity,
        child: child,
      ),
    );
  }

  final ScrollController _controller = ScrollController();

  @override
  Widget buildContent(BuildContext context, List<UserPreview> data) {
    Widget content = Scrollbar(
        controller: _controller,
        child: ListView.builder(
          controller: _controller,
          padding: const EdgeInsets.only(bottom: 8, left: 8),
          primary: false,
          scrollDirection: Axis.horizontal,
          itemCount: data.length,
          itemBuilder: (context, index) {
            return UserPreviewWidget(data[index]).fixWidth(342);
          },
        ));
    if (App.isDesktop) {
      content = ScrollbarTheme.merge(
          data: const ScrollbarThemeData(
              thickness: 6,
              hoveringThickness: 6,
              mainAxisMargin: 4,
              hoveringPadding: EdgeInsets.zero,
              padding: EdgeInsets.zero,
              hoveringMainAxisMargin: 4,
              crossAxisMargin: 0,
              hoveringCrossAxisMargin: 0),
          child: content);
    } else {
      content = ScrollbarTheme.merge(
          data: const ScrollbarThemeData(
              thickness: 4,
              hoveringThickness: 4,
              mainAxisMargin: 4,
              hoveringPadding: EdgeInsets.zero,
              padding: EdgeInsets.zero,
              hoveringMainAxisMargin: 4,
              crossAxisMargin: 0,
              hoveringCrossAxisMargin: 0),
          child: content);
    }
    return MediaQuery.removePadding(
        context: context, removeBottom: true, child: content);
  }

  @override
  Future<Res<List<UserPreview>>> loadData() {
    return Network().relatedUsers(widget.uid);
  }
}
