import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'matrix.dart';

enum Themes {
  light,
  dark,
  system,
}

final ThemeData lightTheme = ThemeData(
  primaryColorDark: Colors.white,
  primaryColorLight: Color(0xff121212),
  brightness: Brightness.light,
  primaryColor: Color(0xFF5625BA),
  backgroundColor: Colors.white,
  secondaryHeaderColor: Color(0xFFECECF2),
  scaffoldBackgroundColor: Colors.white,
  snackBarTheme: SnackBarThemeData(
    behavior: kIsWeb ? SnackBarBehavior.floating : SnackBarBehavior.fixed,
  ),
  dialogTheme: DialogTheme(
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(8.0),
    ),
  ),
  popupMenuTheme: PopupMenuThemeData(
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(8.0),
    ),
  ),
  appBarTheme: AppBarTheme(
    brightness: Brightness.light,
    color: Colors.white,
    textTheme: TextTheme(
      headline6: TextStyle(
        color: Colors.black,
        fontSize: 20,
      ),
    ),
    iconTheme: IconThemeData(color: Colors.black),
  ),
);

final ThemeData darkTheme = ThemeData.dark().copyWith(
  primaryColorDark: Color(0xff1B1B1B),
  primaryColorLight: Colors.white,
  primaryColor: Color(0xFF8966CF),
  errorColor: Color(0xFFCF6679),
  backgroundColor: Color(0xff121212),
  scaffoldBackgroundColor: Color(0xff1B1B1B),
  accentColor: Color(0xFFF5B4D2),
  secondaryHeaderColor: Color(0xff202020),
  snackBarTheme: SnackBarThemeData(
    behavior: kIsWeb ? SnackBarBehavior.floating : SnackBarBehavior.fixed,
  ),
  dialogTheme: DialogTheme(
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(8.0),
    ),
  ),
  popupMenuTheme: PopupMenuThemeData(
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(8.0),
    ),
  ),
  appBarTheme: AppBarTheme(
    brightness: Brightness.dark,
    color: Color(0xff1D1D1D),
    textTheme: TextTheme(
      headline6: TextStyle(
        color: Colors.white,
        fontSize: 20,
      ),
    ),
    iconTheme: IconThemeData(color: Colors.white),
  ),
);

final ThemeData amoledTheme = ThemeData.dark().copyWith(
  primaryColorDark: Color(0xff121212),
  primaryColorLight: Colors.white,
  primaryColor: Color(0xFF8966CF),
  errorColor: Color(0xFFCF6679),
  backgroundColor: Colors.black,
  scaffoldBackgroundColor: Colors.black,
  accentColor: Color(0xFFF5B4D2),
  secondaryHeaderColor: Color(0xff1D1D1D),
  snackBarTheme: SnackBarThemeData(
    behavior: kIsWeb ? SnackBarBehavior.floating : SnackBarBehavior.fixed,
  ),
  dialogTheme: DialogTheme(
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(8.0),
    ),
  ),
  popupMenuTheme: PopupMenuThemeData(
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(8.0),
    ),
  ),
  appBarTheme: AppBarTheme(
    brightness: Brightness.dark,
    color: Color(0xff1D1D1D),
    textTheme: TextTheme(
      headline6: TextStyle(
        color: Colors.white,
        fontSize: 20,
      ),
    ),
    iconTheme: IconThemeData(color: Colors.white),
  ),
);

Color chatListItemColor(BuildContext context, bool activeChat) =>
    Theme.of(context).brightness == Brightness.light
        ? activeChat ? Color(0xFFE8E8E8) : Colors.white
        : activeChat
            ? ThemeSwitcherWidget.of(context).amoledEnabled
                ? Color(0xff121212)
                : Colors.black
            : ThemeSwitcherWidget.of(context).amoledEnabled
                ? Colors.black
                : Color(0xff121212);

Color blackWhiteColor(BuildContext context) =>
    Theme.of(context).brightness == Brightness.light
        ? Colors.white
        : Colors.black;

class ThemeSwitcher extends InheritedWidget {
  final ThemeSwitcherWidgetState data;

  const ThemeSwitcher({
    Key key,
    @required this.data,
    @required Widget child,
  })  : assert(child != null),
        super(key: key, child: child);

  @override
  bool updateShouldNotify(ThemeSwitcher old) {
    return this != old;
  }
}

class ThemeSwitcherWidget extends StatefulWidget {
  final Widget child;

  ThemeSwitcherWidget({Key key, @required this.child})
      : assert(child != null),
        super(key: key);

  @override
  ThemeSwitcherWidgetState createState() => ThemeSwitcherWidgetState();

  /// Returns the (nearest) Client instance of your application.
  static ThemeSwitcherWidgetState of(BuildContext context) {
    var newState =
        (context.dependOnInheritedWidgetOfExactType<ThemeSwitcher>()).data;
    newState.context = context;
    return newState;
  }
}

class ThemeSwitcherWidgetState extends State<ThemeSwitcherWidget> {
  ThemeData themeData;
  Themes selectedTheme;
  bool amoledEnabled;
  @override
  BuildContext context;

  Future loadSelection(MatrixState matrix) async {
    String item = await matrix.store.getItem('theme') ?? 'light';
    selectedTheme =
        Themes.values.firstWhere((e) => e.toString() == 'Themes.' + item);

    amoledEnabled = (await matrix.store.getItem('amoled_enabled') ?? 'false')
            .toLowerCase() ==
        'true';

    switchTheme(matrix, selectedTheme, amoledEnabled);
    return;
  }

  void switchTheme(
      MatrixState matrix, Themes newTheme, bool amoled_enabled) async {
    ThemeData theme;
    switch (newTheme) {
      case Themes.light:
        theme = lightTheme;
        break;
      case Themes.dark:
        if (amoled_enabled) {
          theme = amoledTheme;
        } else {
          theme = darkTheme;
        }
        break;
      case Themes.system:
        // This needs to be a low level call as we don't have a MaterialApp yet
        var brightness =
            MediaQueryData.fromWindow(WidgetsBinding.instance.window)
                .platformBrightness;
        if (brightness == Brightness.dark) {
          if (amoled_enabled) {
            theme = amoledTheme;
          } else {
            theme = darkTheme;
          }
        } else {
          theme = lightTheme;
        }
        break;
    }

    await saveThemeValue(matrix, newTheme);
    await saveAmoledEnabledValue(matrix, amoled_enabled);
    setState(() {
      amoledEnabled = amoled_enabled;
      selectedTheme = newTheme;
      themeData = theme;
    });
  }

  Future saveThemeValue(MatrixState matrix, Themes value) async {
    await matrix.store.setItem('theme', value.toString().split('.').last);
  }

  Future saveAmoledEnabledValue(MatrixState matrix, bool value) async {
    await matrix.store.setItem('amoled_enabled', value.toString());
  }

  void setup() async {
    final matrix = Matrix.of(context);
    await loadSelection(matrix);

    if (selectedTheme == null) {
      switchTheme(matrix, Themes.light, false);
    } else {
      switch (selectedTheme) {
        case Themes.light:
          switchTheme(matrix, Themes.light, false);
          break;
        case Themes.dark:
          if (amoledEnabled) {
            switchTheme(matrix, Themes.dark, true);
          } else {
            switchTheme(matrix, Themes.dark, false);
          }
          break;
        case Themes.system:
          switchTheme(matrix, Themes.system, false);
          break;
      }
    }
  }

  @override
  void initState() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (amoledEnabled == null || selectedTheme == null) {
        setup();
      }
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    if (themeData == null) {
      // This needs to be a low level call as we don't have a MaterialApp yet
      var brightness = MediaQueryData.fromWindow(WidgetsBinding.instance.window)
          .platformBrightness;
      if (brightness == Brightness.dark) {
        themeData = darkTheme;
      } else {
        themeData = lightTheme;
      }
      return ThemeSwitcher(
        data: this,
        child: widget.child,
      );
    } else {
      return ThemeSwitcher(
        data: this,
        child: widget.child,
      );
    }
  }
}
