import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import 'package:result_monad/result_monad.dart';

import '../controls/html_text_viewer_control.dart';
import '../controls/login_aware_cached_network_image.dart';
import '../controls/padding.dart';
import '../globals.dart';
import '../models/connection.dart';
import '../models/exec_error.dart';
import '../routes.dart';
import '../services/connections_manager.dart';
import '../services/feature_version_checker.dart';
import '../services/follow_requests_manager.dart';
import '../services/network_status_service.dart';
import '../services/notifications_manager.dart';
import '../utils/active_profile_selector.dart';
import '../utils/url_opening_utils.dart';

class FollowRequestAdjudicationScreen extends StatefulWidget {
  final String userId;

  const FollowRequestAdjudicationScreen({super.key, required this.userId});

  @override
  State<FollowRequestAdjudicationScreen> createState() =>
      _FollowRequestAdjudicationScreenState();
}

class _FollowRequestAdjudicationScreenState
    extends State<FollowRequestAdjudicationScreen> {
  var processing = false;

  @override
  Widget build(BuildContext context) {
    final nss = getIt<NetworkStatusService>();
    final fm =
        getIt<ActiveProfileSelector<FollowRequestsManager>>().activeEntry.value;
    final cm = context
        .watch<ActiveProfileSelector<ConnectionsManager>>()
        .activeEntry
        .value;

    late final Result<Connection, ExecError> result;
    if (getIt<FriendicaVersionChecker>()
        .canUseFeature(RelaticaFeatures.usingActualFollowRequests)) {
      result = fm
          .getByUserId(widget.userId)
          .mapValue((request) => request.connection);
    } else {
      result = cm.getById(widget.userId, forceUpdate: true);
    }

    late final Widget body;
    if (result.isFailure) {
      if (result.error.type == ErrorType.notFound &&
          nss.connectionUpdateStatus.value) {
        fm.update();
        body = const Text('Loading...');
      } else {
        body = Text('Error getting request info: ${result.error}');
      }
    } else {
      final contact = result.value;
      final contactStatus = cm
          .getById(widget.userId, forceUpdate: true)
          .getValueOrElse(() => Connection(status: ConnectionStatus.none))
          .status;

      switch (contactStatus) {
        case ConnectionStatus.theyFollowYou:
        case ConnectionStatus.youFollowThem:
        case ConnectionStatus.none:
          body = _buildMainPanel(context, contact, cm, fm);
          break;
        case ConnectionStatus.mutual:
          body = const Text('Already allowed them to connect');
          break;
        case ConnectionStatus.you:
        case ConnectionStatus.unknown:
          body = Text(nss.connectionUpdateStatus.value
              ? 'Loading...'
              : 'Invalid state, nothing to do here: ${contact.status}');
          break;
        case ConnectionStatus.blocked:
          // we should never get here because a blocked user shouldn't be allowed to create a connection request.
          body = const Text(
            'Use is blocked. Unblock to accept connection request.',
          );
          break;
      }
    }

    return Scaffold(
      appBar: AppBar(
          title: const Text(
        'Accept Request?',
      )),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Center(child: body),
      ),
    );
  }

  Widget _buildMainPanel(
    BuildContext context,
    Connection contact,
    ConnectionsManager connectionsManager,
    FollowRequestsManager followRequestsManager,
  ) {
    return SingleChildScrollView(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.start,
        children: [
          LoginAwareCachedNetworkImage(imageUrl: contact.avatarUrl.toString()),
          Row(
            crossAxisAlignment: CrossAxisAlignment.center,
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                '${contact.name}(${contact.handle})',
                style: Theme.of(context).textTheme.titleLarge,
              ),
              const HorizontalPadding(),
            ],
          ),
          const VerticalPadding(),
          Wrap(
            runSpacing: 5.0,
            spacing: 5.0,
            alignment: WrapAlignment.center,
            children: [
              ElevatedButton(
                onPressed: processing
                    ? null
                    : () async => await accept(connectionsManager,
                        followRequestsManager, contact, true),
                child: const Text('Accept and follow back'),
              ),
              ElevatedButton(
                onPressed: processing
                    ? null
                    : () async => accept(connectionsManager,
                        followRequestsManager, contact, false),
                child: const Text("Accept but don't follow back"),
              ),
              ElevatedButton(
                onPressed: processing
                    ? null
                    : () async => reject(
                        connectionsManager, followRequestsManager, contact),
                child: const Text('Reject'),
              ),
              ElevatedButton(
                onPressed: processing
                    ? null
                    : () async => ignore(
                        connectionsManager, followRequestsManager, contact),
                child: const Text('Ignore (Rejects but user cannot ask again)'),
              ),
            ],
          ),
          const VerticalPadding(),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              ElevatedButton(
                  onPressed: () => context.pushNamed(
                        ScreenPaths.userPosts,
                        pathParameters: {'id': contact.id},
                      ),
                  child: const Text('Posts')),
              ElevatedButton(
                onPressed: () async =>
                    await openProfileExternal(context, contact),
                child: const Text('Open In Browser'),
              ),
            ],
          ),
          const VerticalPadding(),
          HtmlTextViewerControl(
            content: contact.note,
            onTapUrl: (url) async {
              return await openUrlStringInSystembrowser(context, url, 'link');
            },
          ),
          const VerticalPadding(),
          Text(
              '#Followers: ${contact.followerCount} followers, #Following, ${contact.followingCount}, #Statuses: ${contact.statusesCount}'),
          const VerticalPadding(),
          Text('Last Status: ${contact.lastStatus ?? "Unknown"}'),
        ],
      ),
    );
  }

  Future<void> accept(
    ConnectionsManager manager,
    FollowRequestsManager followRequestsManager,
    Connection contact,
    bool followBack,
  ) async {
    setState(() {
      processing = true;
    });

    await manager.acceptFollowRequest(contact);
    if (followBack) {
      await manager.follow(contact);
    }

    _performUpdates(followRequestsManager);

    setState(() {
      processing = false;
    });

    if (mounted && context.canPop()) {
      context.pop();
    }
  }

  Future<void> reject(ConnectionsManager manager,
      FollowRequestsManager followRequestsManager, Connection contact) async {
    setState(() {
      processing = true;
    });

    await manager.rejectFollowRequest(contact);

    _performUpdates(followRequestsManager);
    setState(() {
      processing = false;
    });

    if (mounted && context.canPop()) {
      context.pop();
    }
  }

  Future<void> ignore(ConnectionsManager manager,
      FollowRequestsManager followRequestsManager, Connection contact) async {
    setState(() {
      processing = true;
    });

    await manager.ignoreFollowRequest(contact);
    _performUpdates(followRequestsManager);

    setState(() {
      processing = false;
    });

    if (mounted && context.canPop()) {
      context.pop();
    }
  }

  void _performUpdates(FollowRequestsManager followRequestsManager) {
    followRequestsManager.update();
    getIt<ActiveProfileSelector<NotificationsManager>>()
        .activeEntry
        .andThenSuccess((m) => m.refreshNotifications());
  }
}
