import 'package:flutter/material.dart';
import 'package:voyagehandbook/api/classes.dart';
import 'package:voyagehandbook/api/wikimedia.dart';
import 'package:voyagehandbook/util/storage.dart';
import 'package:voyagehandbook/views/pageview.dart';

import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../util/drawer.dart';

/*
        Voyage Handbook - The open-source WikiVoyage reader
        Copyright (C) 2023 Matyáš Caras

        This program is free software: you can redistribute it and/or modify
        it under the terms of the GNU General Public License version 3 as published by
        the Free Software Foundation.

        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.

        You should have received a copy of the GNU General Public License
        along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

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

  @override
  State<SearchView> createState() => _SearchViewState();
}

class _SearchViewState extends State<SearchView> {
  final _searchController = TextEditingController();
  var _searchResults = <SearchResponse>[];
  var _showBox = false;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar:
          AppBar(title: Text(AppLocalizations.of(context)!.searchAppBarTitle)),
      drawer: genDrawer(2, context),
      body: SingleChildScrollView(
        physics: const AlwaysScrollableScrollPhysics(),
        child: Center(
          child: SizedBox(
            height: MediaQuery.of(context).size.height,
            width: MediaQuery.of(context).size.width * 0.9,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                TextField(
                  controller: _searchController,
                ),
                TextButton(
                  onPressed: () async {
                    if (_searchController.text == "") return;
                    _showBox = true;
                    setState(() {});
                    var r = await WikiApi.search(_searchController.text);
                    _searchResults = r;
                    setState(() {});
                  },
                  child: Text(AppLocalizations.of(context)!.search),
                ),
                const SizedBox(
                  height: 15,
                ),
                AnimatedOpacity(
                  opacity: (!_showBox) ? 0 : 1,
                  duration: const Duration(milliseconds: 500),
                  child: SizedBox(
                    height: MediaQuery.of(context).size.height -
                        301, // TODO: maybe not responsive?
                    width: MediaQuery.of(context).size.width * 0.9,
                    child: Container(
                      decoration: BoxDecoration(
                        border: Border.all(
                            color: Theme.of(context)
                                .colorScheme
                                .secondaryContainer,
                            width: 1),
                        borderRadius: BorderRadius.circular(4),
                      ),
                      child: (_searchResults.isNotEmpty)
                          ? ListView.builder(
                              itemBuilder: (context, index) {
                                var span = <TextSpan>[];
                                var searchMatches = RegExp(
                                        r'<span class="searchmatch">.+?<\/span>')
                                    .allMatches(_searchResults[index].excerpt);
                                if (searchMatches.isEmpty) {
                                  span = [
                                    TextSpan(
                                        text: _searchResults[index].excerpt)
                                  ];
                                } else {
                                  // create emphasis on words matching search per the span element from API
                                  var text = _searchResults[index].excerpt;
                                  for (var match in searchMatches) {
                                    var split = text.split(match
                                        .group(0)!); // split by span element
                                    span.add(TextSpan(
                                        text:
                                            split[0])); // add text before span
                                    span.add(
                                      TextSpan(
                                        text: match.group(0)!.replaceAll(
                                            RegExp(r'<\/?span.*?>'), ""),
                                        style: const TextStyle(
                                            fontWeight: FontWeight.bold),
                                      ),
                                    ); // add span as bold

                                    text = text
                                        .replaceFirst(
                                            (split.isNotEmpty) ? split[0] : "",
                                            "")
                                        .replaceFirst(match.group(0)!,
                                            ""); // set text for next span to add
                                  }
                                  span.add(
                                    TextSpan(text: text),
                                  ); // add text we didn't add before
                                }
                                return Padding(
                                  padding:
                                      const EdgeInsets.only(left: 8, right: 8),
                                  child: SizedBox(
                                    height: 150,
                                    child: Card(
                                      elevation: 2,
                                      child: InkWell(
                                        onLongPress: () {
                                          // Show download dialog
                                          showDialog(
                                            context: context,
                                            builder: (_) => AlertDialog(
                                              title: Text(
                                                  AppLocalizations.of(context)!
                                                      .offlineTitle),
                                              content: Text(
                                                AppLocalizations.of(context)!
                                                    .offlineDialog(
                                                        _searchResults[index]
                                                            .title),
                                              ),
                                              actions: [
                                                TextButton(
                                                  onPressed: () async {
                                                    Navigator.of(context).pop();
                                                    showDialog(
                                                      context: context,
                                                      barrierDismissible: false,
                                                      builder: (_) => Dialog(
                                                        child: SizedBox(
                                                          height: 100,
                                                          child: Row(
                                                            children: [
                                                              const Padding(
                                                                padding:
                                                                    EdgeInsets
                                                                        .all(
                                                                            10),
                                                                child:
                                                                    CircularProgressIndicator(),
                                                              ),
                                                              Text(AppLocalizations
                                                                      .of(context)!
                                                                  .downloading)
                                                            ],
                                                          ),
                                                        ),
                                                      ),
                                                    );
                                                    try {
                                                      await StorageAccess
                                                          .downloadArticle(
                                                              _searchResults[
                                                                      index]
                                                                  .key,
                                                              _searchResults[
                                                                      index]
                                                                  .title);
                                                      if (!mounted) return;
                                                      Navigator.of(context)
                                                          .pop();
                                                      ScaffoldMessenger.of(
                                                              context)
                                                          .clearSnackBars();
                                                      ScaffoldMessenger.of(
                                                              context)
                                                          .showSnackBar(
                                                        SnackBar(
                                                          content: Text(
                                                              AppLocalizations.of(
                                                                      context)!
                                                                  .downloadComplete),
                                                          duration:
                                                              const Duration(
                                                                  seconds: 4),
                                                        ),
                                                      );
                                                    } catch (e) {
                                                      Navigator.of(context)
                                                          .pop();
                                                      showDialog(
                                                        context: context,
                                                        builder: (_) =>
                                                            AlertDialog(
                                                          title: Text(
                                                              AppLocalizations.of(
                                                                      context)!
                                                                  .error),
                                                          content:
                                                              SingleChildScrollView(
                                                            child: Text(
                                                                e.toString()),
                                                          ),
                                                          actions: [
                                                            TextButton(
                                                              onPressed: () =>
                                                                  Navigator.of(
                                                                          context)
                                                                      .pop(),
                                                              child: Text(
                                                                  AppLocalizations.of(
                                                                          context)!
                                                                      .ok),
                                                            )
                                                          ],
                                                        ),
                                                      );
                                                    }
                                                  },
                                                  child: Text(
                                                      AppLocalizations.of(
                                                              context)!
                                                          .yes),
                                                ),
                                                TextButton(
                                                  onPressed: () =>
                                                      Navigator.of(context)
                                                          .pop(),
                                                  child: Text(
                                                      AppLocalizations.of(
                                                              context)!
                                                          .no),
                                                ),
                                              ],
                                            ),
                                          );
                                        },
                                        onTap: () {
                                          Navigator.of(context).push(
                                            MaterialPageRoute(
                                              builder: (c) => ArticleView(
                                                pageKey:
                                                    _searchResults[index].key,
                                                name:
                                                    _searchResults[index].title,
                                              ),
                                            ),
                                          );
                                        },
                                        child: Padding(
                                          padding: const EdgeInsets.all(8.0),
                                          child: Column(
                                            children: [
                                              Row(children: [
                                                Text(
                                                  _searchResults[index].title,
                                                  style: const TextStyle(
                                                      fontWeight:
                                                          FontWeight.bold,
                                                      fontSize:
                                                          16), // TODO: responsive sizing
                                                ),
                                                if (_searchResults[index]
                                                    .downloaded)
                                                  const SizedBox(
                                                    width: 15,
                                                  ),
                                                if (_searchResults[index]
                                                    .downloaded)
                                                  const Icon(
                                                    Icons.download,
                                                    size: 15,
                                                  ),
                                              ]),
                                              const SizedBox(
                                                height: 10,
                                              ),
                                              RichText(
                                                textAlign: TextAlign.justify,
                                                text: TextSpan(children: span),
                                              ),
                                              const SizedBox(
                                                height: 10,
                                              )
                                            ],
                                          ),
                                        ),
                                      ),
                                    ),
                                  ),
                                );
                              },
                              itemCount: _searchResults.length,
                            )
                          : const SizedBox(
                              height: 50,
                              width: 50,
                              child: CircularProgressIndicator(),
                            ),
                    ),
                  ),
                )
              ],
            ),
          ),
        ),
      ),
    );
  }
}
