import 'dart:async';
import 'dart:convert';

import 'package:checker/base/base_screen.dart';
import 'package:checker/base/base_state.dart';
import 'package:checker/common.dart';
import 'package:checker/consts.dart';
import 'package:checker/db.dart';
import 'package:checker/network.dart';
import 'package:checker/resources.dart';
import 'package:checker/screens/faq.dart';
import 'package:checker/screens/finish_registration.dart';
import 'package:checker/screens/purchase.dart';
import 'package:checker/screens/registration.dart';
import 'package:checker/screens/settings.dart';
import 'package:checker/strings.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart';

// FIXME: Сделать запуск всех экранов из одной точки через метод showNextScreen()
class SplashScreen extends BaseScreen {

  SplashScreen(SqliteHelper helper, String app) : super(helper, app);

  @override
  State createState() => new _SplashScreenState(helper, app);
}

class _SplashScreenState extends BaseState<SplashScreen> {

  _SplashScreenState(SqliteHelper helper, String app) : super(helper, app);
  bool a = true;

  bool isAutomaticallyImplyLeading() => false;

  @override
  void initState() {
    init();
    super.initState();
  }

  @override
  Widget build(BuildContext ctx) {
    return !a ? new Container(
      decoration: new BoxDecoration(
        image: new DecorationImage(
          image: new ExactAssetImage(Resources.getSplash(null)),
          fit:  BoxFit.cover))) : getScreenContent();
  }

  @override
  Widget getScreenContent() {
    return new Stack(children: <Widget>[
            getBackground(),
            getLogo(),
            new Align(
                alignment: FractionalOffset.bottomRight,
                child: new Container(
                    margin: new EdgeInsets.only(right: 11.0, bottom: 5.0),
                    child: new Image.asset(powered_by_dinect_splash_png,
                        height: 16.0, width: 122.0)))
          ]);
  }

  /// Возвращает столбец с логотипом приложения и текстом под ним.
  /// Столбец занимает не все доступное пространство, а необходимый минимум в центре экрана.
  getLogo() {
    return new Center(
        child: new Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
      new Image.asset(Resources.getLogo(app), height: 112.0, width: 252.0),
      new Image.asset(splash_text_png, height: 40.0, width: 240.0)
    ]));
  }

  showNextScreen(Widget screen) {
    new Future.delayed(const Duration(milliseconds: 200), () {
      var route = new MaterialPageRoute<String>(
        builder: (BuildContext context) => screen, fullscreenDialog: true);
      Navigator.of(context).push(route).then((token) {
        if (token == '') {
          showNextScreen(new RegistrationScreen(helper, app));
        } else if (token != null) {
          _initAndStartScanner(context, app, token, helper);
        } else {
          print('Произошла непредусмотренная ошибка в логике приложения');
          helper.getToken().then((token) {
            _initAndStartScanner(context, app, token, helper);
          });
        }
      });
    });
  }

  /// Запуск следующего экрана приложения.
  init() async {
    String token = await helper.getToken();
    // В случае, если в приложении отсутствует токен,
    // необходимо запустить регистрацию кассы.
    if (token == null) {
      showNextScreen(new RegistrationScreen(helper, app));
    } else {
      if (await platform.invokeMethod('isOnline')) {
        getCheckTokenStatusRequest(token).then((statusResponse) {
          handleStatusResponse(statusResponse, helper);
        }).catchError((error) {
          print(error.toString());
        });
      }
    }
  }

  /// Обработка ответа.
  /// В случае, если токен был удален может прийти active: false, либо 404.
  /// Если токен не активен, попробовать создать его еще раз.
  handleStatusResponse(var statusResponse, SqliteHelper helper) async {
    int code = statusResponse.statusCode;
    if (code == 404) {
      helper.clear().then((result) {
        showNextScreen(new RegistrationScreen(helper, app));
      });
    } else {
      Map status = json.decode(statusResponse.body);
      bool active = status['active'] == null ? false : status['active'];

      if (active) {
        helper.getToken().then((token) {
          _initAndStartScanner(context, app, token, helper);
        });
      } else {
        if (await platform.invokeMethod('isOnline')) {
          _createToken(helper);
        }
      }
    }
  }

  ///  Отправляется запрос на создание токена.
  ///
  ///  Если вернулся код 409, значит такой токен уже существует и активирован.
  ///  Нужно направить пользователя на экран подтверждения активации.
  ///
  ///  Если вернулся код 200, значит токен был ранее удален и только что снова создался.
  ///  Нужно удалить его и направить пользователя на экран регистрации.
  _createToken(SqliteHelper helper) async {
    String merchantID = await helper.getMerchantID();
    String posID = await helper.getPosID();

    getCreateTokenRequest({'merchant_shop': merchantID, 'pos': posID})
        .then((response) {
      if (response.statusCode == 409) {
        showNextScreen(new FinishRegistrationScreen(helper, app));
      } else if (response.statusCode == 201) {
        clearToken(response, helper);
      }
    }).catchError((error) {
      print(error.toString());
    });
  }

  /// Очищаем бд, делаем запрос на удаление токена.
  Future clearToken(Response response, SqliteHelper helper) async {
    helper.clear().then((_) {
      Map parsedMap = json.decode(response.body);
      getDeleteTokenRequest(parsedMap['token']).then((_) {
        showNextScreen(new RegistrationScreen(helper, app));
      }).catchError((error) {
        print(error.toString());
      });
    });
  }


  /// Запуск спецефичной для каждой платформы части приложения - сканера.
  /// Может производиться с нескольких экранов (splash, finish_registration).
  _initAndStartScanner(BuildContext context, String app, String token,
    SqliteHelper helper) {
    // Канал ловит вызовы методов из "нативной" части приложения.
    // Могут быть вызваны либо exit либо faq, либо purchase.

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

    platform.setMethodCallHandler((MethodCall call) async {
      print(this.toString());
      if (call.method == 'findUser') {

        try {

          Response userResponse;

          switch (call.arguments[1]) {
            case 'card':
              userResponse = await getUserByCard(call.arguments[0], token);
              break;
            case 'phone':
              userResponse = await getUserByPhone(call.arguments[0], token);
              break;
          }

          if (userResponse != null) {
            print('I have user in method handler!');
            List<dynamic> users = json.decode(userResponse.body);
            if (users.length > 0) {
              return users[0];
            } else {
              throw new FlutterError("Users not found");
            }
          } else {
            throw new FlutterError("Users not found");
          }
        } catch (error) {
          print(error.toString());
          throw new FlutterError("Users not found");
        }

      } else if (call.method == 'faq') {
        new Future.delayed(const Duration(milliseconds: 200), () {
          var route = new MaterialPageRoute<Null>(
            builder: (BuildContext context) => new FAQScreen(helper, app), fullscreenDialog: true);
          Navigator.of(context).push(route).then((_) {
            _initAndStartScanner(context, app, token, helper);
          });
        });
      } else if (call.method == 'settings') {
        new Future.delayed(const Duration(milliseconds: 200), () {
          var route = new MaterialPageRoute<String>(
            builder: (BuildContext context) => new SettingsScreen(helper, app, true), fullscreenDialog: true);
            Navigator.of(context).push(route).then((result) {
              if (result != null) {
                showNextScreen(new RegistrationScreen(helper, app));
              } else {
                _initAndStartScanner(context, app, token, helper);
              }
            });
          });
      } else {
        String userString = call.arguments[0] is String
          ? call.arguments[0]
          : json.encode(call.arguments[0]);
        print(userString);
        String card = call.arguments[1];
        showNextScreen(new PurchaseScreen(helper, app, userString, card));
      }
    });

    platform.invokeMethod('getEndpoint').then((url) {
      platform.invokeMethod('getAppToken').then((appToken) {
        Map<String, String> args = StringsLocalization.strings;
        args['token'] = token;
        args['url'] = url;
        args['appToken'] = appToken;
        args['localeCode'] = StringsLocalization.localeCode;
        args['color'] = Resources
          .getPrimaryColor(app)
          .value
          .toString();
        platform.invokeMethod('startScanner', args);
      });
    });
  }
}
