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

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/finish_registration.dart';
import 'package:checker/screens/registration.dart';
import 'package:checker/strings.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:intl/intl.dart';

class SplashScreen extends StatefulWidget {
  @override
  State createState() => new _SplashScreenState();
}

class _SplashScreenState extends BaseState<SplashScreen> {
  @override
  Widget build(BuildContext ctx) {
    if (helper == null) {
      helper = new SqliteHelper();
      helper.open().then((_) {
        if (app == null) {
          platform.invokeMethod('getFlavor').then((flavor) {
            app = flavor;
            setState(() {
              onStart();
            });
          });
        }
      });
    }
    return getScreenContent();
  }

  void onStart() {
    helper.getLocale().then((locale) {
      if (locale == null) {
        initWithSystemValue();
      } else {
        initWithSavedValue(locale);
      }
    });
  }

  void initWithSystemValue() {
    platform.invokeMethod('getLocale').then((locale) {
      helper.getSettings().then((settings) {
        if (settings == null) {
          createSettingsTable(locale);
        } else {
          initLocale(locale, () {
            showNext();
          });
        }
      });
    });
  }

  void initWithSavedValue(String locale) {
    initLocale(locale, () {
      showNext();
    });
  }

  void createSettingsTable(String locale) {
    platform.invokeMethod('getCurrency').then((currency) {
      helper.createAppInfo(currency);
      initLocale(locale, () {
        showNext();
      });
    });
  }

  void initLocale<T>(String locale, Future<T> onValue()) {
    Intl.defaultLocale = locale;
    StringsLocalization.load(locale).then((_) {
      onValue();
    });
  }

  void showNext() {
    new Future.delayed(const Duration(milliseconds: 1000), () {
      showNextScreen();
    });
  }

  @override
  Widget getScreenContent() {
    return app == null
        ? getBackground()
        : 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() async {
    String token = await helper.getToken();

    // В случае, если в приложении отсутствует токен,
    // необходимо запустить регистрацию кассы.
    if (token == null) {
      pushRouteReplacement(context, 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) {
        pushRouteReplacement(context, new RegistrationScreen(helper, app));
      });
    } else {
      Map status = JSON.decode(statusResponse.body);
      bool active = status['active'] == null ? false : status['active'];

      if (active) {
        startScanner(context, app, 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) {
        pushRouteReplacement(
            context, 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((_) {
        Navigator.of(context).pop();
        pushRouteReplacement(context, new RegistrationScreen(helper, app));
      }).catchError((error) {
        print(error.toString());
      });
    });
  }
}
