import 'dart:async';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:flutter_svg/svg.dart';
import 'package:mobile_nebula/components/SimplePage.dart';
import 'package:mobile_nebula/components/config/ConfigPageItem.dart';
import 'package:mobile_nebula/components/config/ConfigItem.dart';
import 'package:mobile_nebula/components/config/ConfigSection.dart';
import 'package:mobile_nebula/models/HostInfo.dart';
import 'package:mobile_nebula/models/Site.dart';
import 'package:mobile_nebula/screens/SiteLogsScreen.dart';
import 'package:mobile_nebula/screens/SiteTunnelsScreen.dart';
import 'package:mobile_nebula/screens/siteConfig/SiteConfigScreen.dart';
import 'package:mobile_nebula/services/utils.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';

//TODO: If the site isn't active, don't respond to reloads on hostmaps
//TODO: ios is now the problem with connecting screwing our ability to query the hostmap (its a race)

class SiteDetailScreen extends StatefulWidget {
  const SiteDetailScreen({
    Key? key,
    required this.site,
    this.onChanged,
    required this.supportsQRScanning,
  }) : super(key: key);

  final Site site;
  final Function? onChanged;
  final bool supportsQRScanning;

  @override
  _SiteDetailScreenState createState() => _SiteDetailScreenState();
}

class _SiteDetailScreenState extends State<SiteDetailScreen> {
  late Site site;
  late StreamSubscription onChange;
  static const platform = MethodChannel('net.defined.mobileNebula/NebulaVpnService');
  bool changed = false;
  List<HostInfo>? activeHosts;
  List<HostInfo>? pendingHosts;
  RefreshController refreshController = RefreshController(initialRefresh: false);

  @override
  void initState() {
    site = widget.site;
    if (site.connected) {
      _listHostmap();
    }

    onChange = site.onChange().listen((_) {
      // TODO: Gross hack... we get site.connected = true to trigger the toggle before the VPN service has started.
      // If we fetch the hostmap now we'll never get a response. Wait until Nebula is running.
      if (site.status == 'Connected') {
        _listHostmap();
      } else {
        activeHosts = null;
        pendingHosts = null;
      }

      setState(() {});
    }, onError: (err) {
      setState(() {});
      Utils.popError(context, "Error", err);
    });

    super.initState();
  }

  @override
  void dispose() {
    onChange.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final dnIcon =
        Theme.of(context).brightness == Brightness.dark ? 'images/dn-logo-dark.svg' : 'images/dn-logo-light.svg';
    final title = Row(children: [
      site.managed
          ? Padding(padding: EdgeInsets.only(right: 10), child: SvgPicture.asset(dnIcon, width: 12))
          : Container(),
      Expanded(child: Text(site.name, style: TextStyle(fontWeight: FontWeight.bold)))
    ]);

    return SimplePage(
        title: title,
        leadingAction: Utils.leadingBackWidget(context, onPressed: () {
          if (changed && widget.onChanged != null) {
            widget.onChanged!();
          }
          Navigator.pop(context);
        }),
        refreshController: refreshController,
        onRefresh: () async {
          if (site.connected && site.status == "Connected") {
            await _listHostmap();
          }
          refreshController.refreshCompleted();
        },
        child: Column(children: [
          _buildErrors(),
          _buildConfig(),
          site.connected ? _buildHosts() : Container(),
          _buildSiteDetails(),
          _buildDelete(),
        ]));
  }

  Widget _buildErrors() {
    if (site.errors.length == 0) {
      return Container();
    }

    List<Widget> items = [];
    site.errors.forEach((error) {
      items.add(ConfigItem(
          labelWidth: 0, content: Padding(padding: EdgeInsets.symmetric(vertical: 10), child: SelectableText(error))));
    });

    return ConfigSection(
      label: 'ERRORS',
      borderColor: CupertinoColors.systemRed.resolveFrom(context),
      labelColor: CupertinoColors.systemRed.resolveFrom(context),
      children: items,
    );
  }

  Widget _buildConfig() {
    return ConfigSection(children: <Widget>[
      ConfigItem(
          label: Text('Status'),
          content: Row(mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[
            Padding(
                padding: EdgeInsets.only(right: 5),
                child: Text(widget.site.status,
                    style: TextStyle(color: CupertinoColors.secondaryLabel.resolveFrom(context)))),
            Switch.adaptive(
              value: widget.site.connected,
              materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
              onChanged: (v) async {
                try {
                  if (v) {
                    await widget.site.start();
                  } else {
                    await widget.site.stop();
                  }
                } catch (error) {
                  var action = v ? 'start' : 'stop';
                  Utils.popError(context, 'Failed to $action the site', error.toString());
                }
              },
            )
          ])),
      ConfigPageItem(
        label: Text('Logs'),
        onPressed: () {
          Utils.openPage(context, (context) {
            return SiteLogsScreen(site: widget.site);
          });
        },
      ),
    ]);
  }

  Widget _buildHosts() {
    Widget active, pending;

    if (activeHosts == null) {
      active = SizedBox(height: 20, width: 20, child: PlatformCircularProgressIndicator());
    } else {
      active = Text(Utils.itemCountFormat(activeHosts!.length, singleSuffix: "tunnel", multiSuffix: "tunnels"));
    }

    if (pendingHosts == null) {
      pending = SizedBox(height: 20, width: 20, child: PlatformCircularProgressIndicator());
    } else {
      pending = Text(Utils.itemCountFormat(pendingHosts!.length, singleSuffix: "tunnel", multiSuffix: "tunnels"));
    }

    return ConfigSection(
      label: "TUNNELS",
      children: <Widget>[
        ConfigPageItem(
            onPressed: () {
              if (activeHosts == null) return;

              Utils.openPage(
                  context,
                  (context) => SiteTunnelsScreen(
                        pending: false,
                        tunnels: activeHosts!,
                        site: site,
                        onChanged: (hosts) {
                          setState(() {
                            activeHosts = hosts;
                          });
                        },
                        supportsQRScanning: widget.supportsQRScanning,
                      ));
            },
            label: Text("Active"),
            content: Container(alignment: Alignment.centerRight, child: active)),
        ConfigPageItem(
            onPressed: () {
              if (pendingHosts == null) return;

              Utils.openPage(
                  context,
                  (context) => SiteTunnelsScreen(
                        pending: true,
                        tunnels: pendingHosts!,
                        site: site,
                        onChanged: (hosts) {
                          setState(() {
                            pendingHosts = hosts;
                          });
                        },
                        supportsQRScanning: widget.supportsQRScanning,
                      ));
            },
            label: Text("Pending"),
            content: Container(alignment: Alignment.centerRight, child: pending))
      ],
    );
  }

  Widget _buildSiteDetails() {
    return ConfigSection(children: <Widget>[
      ConfigPageItem(
        crossAxisAlignment: CrossAxisAlignment.center,
        content: Text('Configuration'),
        onPressed: () {
          Utils.openPage(context, (context) {
            return SiteConfigScreen(
              site: widget.site,
              onSave: (site) async {
                changed = true;
                setState(() {});
              },
              supportsQRScanning: widget.supportsQRScanning,
            );
          });
        },
      ),
    ]);
  }

  Widget _buildDelete() {
    return Padding(
        padding: EdgeInsets.only(top: 50, bottom: 10, left: 10, right: 10),
        child: SizedBox(
            width: double.infinity,
            child: PlatformElevatedButton(
                child: Text('Delete'),
                color: CupertinoColors.systemRed.resolveFrom(context),
                onPressed: () => Utils.confirmDelete(context, 'Delete Site?', () async {
                      if (await _deleteSite()) {
                        Navigator.of(context).pop();
                      }
                    }))));
  }

  _listHostmap() async {
    try {
      var maps = await site.listAllHostmaps();
      activeHosts = maps["active"];
      pendingHosts = maps["pending"];
      setState(() {});
    } catch (err) {
      Utils.popError(context, 'Error while fetching hostmaps', err.toString());
    }
  }

  Future<bool> _deleteSite() async {
    try {
      var err = await platform.invokeMethod("deleteSite", widget.site.id);
      if (err != null) {
        Utils.popError(context, 'Failed to delete the site', err);
        return false;
      }
    } catch (err) {
      Utils.popError(context, 'Failed to delete the site', err.toString());
      return false;
    }

    if (widget.onChanged != null) {
      widget.onChanged!();
    }
    return true;
  }
}