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

import '../controls/app_bottom_nav_bar.dart';
import '../controls/current_profile_button.dart';
import '../controls/image_control.dart';
import '../controls/responsive_max_width.dart';
import '../controls/search_result_status_control.dart';
import '../controls/standard_app_drawer.dart';
import '../friendica_client/friendica_client.dart';
import '../friendica_client/paging_data.dart';
import '../globals.dart';
import '../models/auth/profile.dart';
import '../models/connection.dart';
import '../models/search_results.dart';
import '../models/search_types.dart';
import '../models/timeline_entry.dart';
import '../routes.dart';
import '../services/auth_service.dart';
import '../services/connections_manager.dart';
import '../services/entry_manager_service.dart';
import '../services/network_status_service.dart';
import '../utils/active_profile_selector.dart';
import '../utils/snackbar_builder.dart';

class SearchScreen extends StatefulWidget {
  const SearchScreen({super.key});

  @override
  State<SearchScreen> createState() => _SearchScreenState();
}

class _SearchScreenState extends State<SearchScreen> {
  static const limit = 50;
  static final _logger = Logger('$SearchScreen');
  var searchTextController = TextEditingController();
  var searchType = SearchTypes.statusesText;
  var searching = false;
  PagingData nextPage = PagingData(limit: limit);
  var searchResult = SearchResults.empty();
  Profile? profileOfSearchRequest;

  PagingData genNextPageData() {
    late final int offset;
    switch (searchType) {
      case SearchTypes.hashTag:
        offset = searchResult.hashtags.length;
        break;
      case SearchTypes.account:
        offset = searchResult.accounts.length;
        break;
      case SearchTypes.statusesText:
        offset = searchResult.statuses.length;
        break;
      case SearchTypes.directLink:
        offset = 0;
        break;
    }

    return PagingData(limit: limit, offset: offset);
  }

  Future<void> updateSearchResults(Profile profile, {bool reset = true}) async {
    print('Starting update');
    if (reset) {
      nextPage = PagingData(limit: limit);
      searchResult = SearchResults.empty();
    }
    setState(() {
      searching = true;
    });

    print('Search $searchType on ${searchTextController.text}');
    final result = await SearchClient(profile)
        .search(searchType, searchTextController.text, nextPage);
    result.match(
      onSuccess: (result) {
        searchResult = reset ? result.data : searchResult.merge(result.data);
        nextPage = result.next ?? genNextPageData();
        profileOfSearchRequest = profile;
      },
      onError: (error) =>
          buildSnackbar(context, 'Error getting search result: $error'),
    );
    setState(() {
      searching = false;
    });
    print('Ending update');
  }

  clearSearchResults() {
    print('Clearing results');
    setState(() {
      searchResult = SearchResults.empty();
      searchTextController.text = '';
      searching = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    _logger.finer('Build');
    final nss = getIt<NetworkStatusService>();
    final profileService = context.watch<AccountsService>();
    final profile = profileService.currentProfile;
    late Widget body;

    if (profile != profileOfSearchRequest) {
      clearSearchResults();
    }

    if (searchResult.isEmpty && searching) {
      body = Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'Searching for ${searchType.toLabel()} on: ${searchTextController.text}',
            ),
          ],
        ),
      );
    } else {
      body = ResponsiveMaxWidth(child: buildResultBody(profile));
    }

    return Scaffold(
      drawer: const StandardAppDrawer(skipPopDismiss: false),
      body: SafeArea(
        child: RefreshIndicator(
          onRefresh: () async {
            if (nss.searchLoadingStatus.value) {
              return;
            }
            updateSearchResults(profile);
            return;
          },
          child: Column(
            children: [
              Row(
                children: [
                  SizedBox(
                      width: 50.0, child: buildCurrentProfileButton(context)!),
                  Expanded(
                    child: Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: TextField(
                        controller: searchTextController,
                        onSubmitted: (value) {
                          searchTextController.text = value;
                          updateSearchResults(profile);
                        },
                        onTapOutside: (event) {
                          FocusManager.instance.primaryFocus?.unfocus();
                        },
                        decoration: InputDecoration(
                          labelText: searchType == SearchTypes.directLink
                              ? 'URL'
                              : '${searchType.toLabel()} Search Text',
                          alignLabelWithHint: true,
                          border: OutlineInputBorder(
                            borderSide: BorderSide(
                              color: Theme.of(context).colorScheme.background,
                            ),
                            borderRadius: BorderRadius.circular(5.0),
                          ),
                        ),
                      ),
                    ),
                  ),
                  IconButton(
                    onPressed: () {
                      updateSearchResults(profile);
                    },
                    icon: const Icon(Icons.search),
                  ),
                  PopupMenuButton<SearchTypes>(
                      initialValue: searchType,
                      onSelected: (type) {
                        setState(() {
                          searchType = type;
                        });
                      },
                      itemBuilder: (_) => SearchTypes.values
                          .map((e) => PopupMenuItem(
                              value: e,
                              child: Text(
                                e.toLabel(),
                              )))
                          .toList()),
                ],
              ),
              if (searching) const LinearProgressIndicator(),
              Expanded(child: body),
            ],
          ),
        ),
      ),
      bottomNavigationBar: const AppBottomNavBar(
        currentButton: NavBarButtons.search,
      ),
    );
  }

  Widget buildResultBody(Profile profile) {
    _logger.finer('Building search result body with: $searchResult');
    switch (searchType) {
      case SearchTypes.hashTag:
        return buildHashtagResultWidget(profile);
      case SearchTypes.account:
        return buildAccountResultWidget(profile);
      case SearchTypes.statusesText:
        return buildStatusResultWidget(profile);
      case SearchTypes.directLink:
        return buildDirectLinkResult(profile);
    }
  }

  Widget buildHashtagResultWidget(Profile profile) {
    final hashtags = searchResult.hashtags;
    if (hashtags.isEmpty) {
      return buildEmptyResult();
    }
    return ListView.builder(
      physics: const AlwaysScrollableScrollPhysics(),
      itemBuilder: (context, index) {
        if (index == hashtags.length) {
          return TextButton(
            onPressed: () {
              updateSearchResults(profile, reset: false);
            },
            child: const Text('Load more results'),
          );
        }
        return ListTile(
          title: Text(hashtags[index]),
        );
      },
      itemCount: hashtags.length + 1,
    );
  }

  Widget buildAccountResultWidget(Profile profile) {
    final accounts = searchResult.accounts;
    if (accounts.isEmpty) {
      return buildEmptyResult();
    }

    return ListView.builder(
      physics: const AlwaysScrollableScrollPhysics(),
      itemBuilder: (_, index) {
        if (index == accounts.length) {
          return TextButton(
            onPressed: () {
              updateSearchResults(profile, reset: false);
            },
            child: const Text('Load more results'),
          );
        }

        return buildConnectionListTile(accounts[index]);
      },
      itemCount: accounts.length + 1,
    );
  }

  Widget buildStatusResultWidget(Profile profile) {
    final statuses = searchResult.statuses;
    if (statuses.isEmpty) {
      return buildEmptyResult();
    }
    return ListView.builder(
      physics: const AlwaysScrollableScrollPhysics(),
      itemBuilder: (context, index) {
        if (index == statuses.length) {
          return TextButton(
            onPressed: () {
              updateSearchResults(profile, reset: false);
            },
            child: const Text('Load more results'),
          );
        }
        return buildStatusListTile(statuses[index]);
      },
      itemCount: statuses.length + 1,
    );
  }

  Widget buildDirectLinkResult(Profile profile) {
    if (searchResult.isEmpty) {
      return buildEmptyResult();
    }

    return ListView(physics: const AlwaysScrollableScrollPhysics(), children: [
      if (searchResult.statuses.isNotEmpty)
        buildStatusListTile(searchResult.statuses.first),
      if (searchResult.accounts.isNotEmpty)
        buildConnectionListTile(searchResult.accounts.first),
    ]);
  }

  Widget buildEmptyResult() {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text(searchTextController.text.isEmpty
              ? 'Type search text to search'
              : 'No results for ${searchType.toLabel()} search on: ${searchTextController.text}'),
        ],
      ),
    );
  }

  Widget buildConnectionListTile(Connection connection) {
    return ListTile(
      onTap: () async {
        await getIt<ActiveProfileSelector<ConnectionsManager>>()
            .activeEntry
            .andThenSuccessAsync((cm) async {
          final existingData = cm.getById(connection.id);
          if (existingData.isFailure) {
            await cm.fullRefresh(connection);
          }
        });
        if (context.mounted) {
          context.pushNamed(ScreenPaths.userProfile,
              pathParameters: {'id': connection.id});
        }
      },
      leading: ImageControl(
        imageUrl: connection.avatarUrl.toString(),
        iconOverride: const Icon(Icons.person),
        width: 32.0,
        onTap: () => context.pushNamed(ScreenPaths.userProfile,
            pathParameters: {'id': connection.id}),
      ),
      title: Text('${connection.name} (${connection.handle})'),
    );
  }

  Widget buildStatusListTile(TimelineEntry status) {
    return SearchResultStatusControl(status, () async {
      final result = await getIt<ActiveProfileSelector<EntryManagerService>>()
          .activeEntry
          .andThenAsync((em) async => em.refreshStatusChain(status.id));
      if (context.mounted) {
        result.match(
            onSuccess: (entry) =>
                context.push('/post/view/${entry.id}/${status.id}'),
            onError: (error) =>
                buildSnackbar(context, 'Error getting post: $error'));
      }
    });
  }
}
