# -*- coding: utf-8 -*-
from kivy.app import App
from kivy.core.text import LabelBase
from kivy.core.window import Window
from kivy.clock import Clock
from kivy.metrics import dp
from kivy.properties import OptionProperty, AliasProperty, ObjectProperty, \
	StringProperty, ListProperty, BooleanProperty
from kivy.uix.widget import Widget
from kivy.utils import get_color_from_hex
from kivy.atlas import Atlas
from kivymd.color_definitions import colors
from kivymd.material_resources import FONTS, DEVICE_TYPE
from kivymd import images_path

for font in FONTS:
	LabelBase.register(**font)


class ThemeManager(Widget):
	primary_palette = OptionProperty(
			'Blue',
			options=['Pink', 'Blue', 'Indigo', 'BlueGrey', 'Brown',
			         'LightBlue',
			         'Purple', 'Grey', 'Yellow', 'LightGreen', 'DeepOrange',
			         'Green', 'Red', 'Teal', 'Orange', 'Cyan', 'Amber',
			         'DeepPurple', 'Lime'])

	primary_hue = OptionProperty(
			'500',
			options=['50', '100', '200', '300', '400', '500', '600', '700',
			         '800',
			         '900', 'A100', 'A200', 'A400', 'A700'])

	primary_light_hue = OptionProperty(
			'200',
			options=['50', '100', '200', '300', '400', '500', '600', '700',
			         '800',
			         '900', 'A100', 'A200', 'A400', 'A700'])

	primary_dark_hue = OptionProperty(
			'700',
			options=['50', '100', '200', '300', '400', '500', '600', '700',
			         '800',
			         '900', 'A100', 'A200', 'A400', 'A700'])

	def _get_primary_color(self):
		return get_color_from_hex(
				colors[self.primary_palette][self.primary_hue])

	primary_color = AliasProperty(_get_primary_color,
	                              bind=('primary_palette', 'primary_hue'))

	def _get_primary_light(self):
		return get_color_from_hex(
				colors[self.primary_palette][self.primary_light_hue])

	primary_light = AliasProperty(
			_get_primary_light, bind=('primary_palette', 'primary_light_hue'))

	def _get_primary_dark(self):
		return get_color_from_hex(
				colors[self.primary_palette][self.primary_dark_hue])

	primary_dark = AliasProperty(_get_primary_color,
	                             bind=('primary_palette', 'primary_dark_hue'))

	accent_palette = OptionProperty(
			'Amber',
			options=['Pink', 'Blue', 'Indigo', 'BlueGrey', 'Brown',
			         'LightBlue',
			         'Purple', 'Grey', 'Yellow', 'LightGreen', 'DeepOrange',
			         'Green', 'Red', 'Teal', 'Orange', 'Cyan', 'Amber',
			         'DeepPurple', 'Lime'])

	accent_hue = OptionProperty(
			'500',
			options=['50', '100', '200', '300', '400', '500', '600', '700',
			         '800',
			         '900', 'A100', 'A200', 'A400', 'A700'])

	accent_light_hue = OptionProperty(
			'200',
			options=['50', '100', '200', '300', '400', '500', '600', '700',
			         '800',
			         '900', 'A100', 'A200', 'A400', 'A700'])

	accent_dark_hue = OptionProperty(
			'700',
			options=['50', '100', '200', '300', '400', '500', '600', '700',
			         '800',
			         '900', 'A100', 'A200', 'A400', 'A700'])

	def _get_accent_color(self):
		return get_color_from_hex(
				colors[self.accent_palette][self.accent_hue])

	accent_color = AliasProperty(_get_accent_color,
	                             bind=['accent_palette', 'accent_hue'])

	def _get_accent_light(self):
		return get_color_from_hex(
				colors[self.accent_palette][self.accent_light_hue])

	accent_light = AliasProperty(_get_accent_light,
	                             bind=['accent_palette', 'accent_light_hue'])

	def _get_accent_dark(self):
		return get_color_from_hex(
				colors[self.accent_palette][self.accent_dark_hue])

	accent_dark = AliasProperty(_get_accent_dark,
	                            bind=['accent_palette', 'accent_dark_hue'])

	theme_style = OptionProperty('Light', options=['Light', 'Dark'])

	def _get_theme_style(self, opposite):
		if opposite:
			return 'Light' if self.theme_style == 'Dark' else 'Dark'
		else:
			return self.theme_style

	def _get_bg_darkest(self, opposite=False):
		theme_style = self._get_theme_style(opposite)
		if theme_style == 'Light':
			return get_color_from_hex(colors['Light']['StatusBar'])
		elif theme_style == 'Dark':
			return get_color_from_hex(colors['Dark']['StatusBar'])

	bg_darkest = AliasProperty(_get_bg_darkest, bind=['theme_style'])

	def _get_op_bg_darkest(self):
		return self._get_bg_darkest(True)

	opposite_bg_darkest = AliasProperty(_get_op_bg_darkest,
	                                    bind=['theme_style'])

	def _get_bg_dark(self, opposite=False):
		theme_style = self._get_theme_style(opposite)
		if theme_style == 'Light':
			return get_color_from_hex(colors['Light']['AppBar'])
		elif theme_style == 'Dark':
			return get_color_from_hex(colors['Dark']['AppBar'])

	bg_dark = AliasProperty(_get_bg_dark, bind=['theme_style'])

	def _get_op_bg_dark(self):
		return self._get_bg_dark(True)

	opposite_bg_dark = AliasProperty(_get_op_bg_dark, bind=['theme_style'])

	def _get_bg_normal(self, opposite=False):
		theme_style = self._get_theme_style(opposite)
		if theme_style == 'Light':
			return get_color_from_hex(colors['Light']['Background'])
		elif theme_style == 'Dark':
			return get_color_from_hex(colors['Dark']['Background'])

	bg_normal = AliasProperty(_get_bg_normal, bind=['theme_style'])

	def _get_op_bg_normal(self):
		return self._get_bg_normal(True)

	opposite_bg_normal = AliasProperty(_get_op_bg_normal, bind=['theme_style'])

	def _get_bg_light(self, opposite=False):
		theme_style = self._get_theme_style(opposite)
		if theme_style == 'Light':
			return get_color_from_hex(colors['Light']['CardsDialogs'])
		elif theme_style == 'Dark':
			return get_color_from_hex(colors['Dark']['CardsDialogs'])

	bg_light = AliasProperty(_get_bg_light, bind=['theme_style'])

	def _get_op_bg_light(self):
		return self._get_bg_light(True)

	opposite_bg_light = AliasProperty(_get_op_bg_light, bind=['theme_style'])

	def _get_divider_color(self, opposite=False):
		theme_style = self._get_theme_style(opposite)
		if theme_style == 'Light':
			color = get_color_from_hex('000000')
		elif theme_style == 'Dark':
			color = get_color_from_hex('FFFFFF')
		color[3] = .12
		return color

	divider_color = AliasProperty(_get_divider_color, bind=['theme_style'])

	def _get_op_divider_color(self):
		return self._get_divider_color(True)

	opposite_divider_color = AliasProperty(_get_op_divider_color,
	                                       bind=['theme_style'])

	def _get_text_color(self, opposite=False):
		theme_style = self._get_theme_style(opposite)
		if theme_style == 'Light':
			color = get_color_from_hex('000000')
			color[3] = .87
		elif theme_style == 'Dark':
			color = get_color_from_hex('FFFFFF')
		return color

	text_color = AliasProperty(_get_text_color, bind=['theme_style'])

	def _get_op_text_color(self):
		return self._get_text_color(True)

	opposite_text_color = AliasProperty(_get_op_text_color,
	                                    bind=['theme_style'])

	def _get_secondary_text_color(self, opposite=False):
		theme_style = self._get_theme_style(opposite)
		if theme_style == 'Light':
			color = get_color_from_hex('000000')
			color[3] = .54
		elif theme_style == 'Dark':
			color = get_color_from_hex('FFFFFF')
			color[3] = .70
		return color

	secondary_text_color = AliasProperty(_get_secondary_text_color,
	                                     bind=['theme_style'])

	def _get_op_secondary_text_color(self):
		return self._get_secondary_text_color(True)

	opposite_secondary_text_color = AliasProperty(_get_op_secondary_text_color,
	                                              bind=['theme_style'])

	def _get_icon_color(self, opposite=False):
		theme_style = self._get_theme_style(opposite)
		if theme_style == 'Light':
			color = get_color_from_hex('000000')
			color[3] = .54
		elif theme_style == 'Dark':
			color = get_color_from_hex('FFFFFF')
		return color

	icon_color = AliasProperty(_get_icon_color,
	                           bind=['theme_style'])

	def _get_op_icon_color(self):
		return self._get_icon_color(True)

	opposite_icon_color = AliasProperty(_get_op_icon_color,
	                                    bind=['theme_style'])

	def _get_disabled_hint_text_color(self, opposite=False):
		theme_style = self._get_theme_style(opposite)
		if theme_style == 'Light':
			color = get_color_from_hex('000000')
			color[3] = .26
		elif theme_style == 'Dark':
			color = get_color_from_hex('FFFFFF')
			color[3] = .30
		return color

	disabled_hint_text_color = AliasProperty(_get_disabled_hint_text_color,
	                                         bind=['theme_style'])

	def _get_op_disabled_hint_text_color(self):
		return self._get_disabled_hint_text_color(True)

	opposite_disabled_hint_text_color = AliasProperty(
			_get_op_disabled_hint_text_color, bind=['theme_style'])

	# Hardcoded because muh standard
	def _get_error_color(self):
		return get_color_from_hex(colors['Red']['A700'])

	error_color = AliasProperty(_get_error_color)

	def _get_ripple_color(self):
		return self._ripple_color

	def _set_ripple_color(self, value):
		self._ripple_color = value

	_ripple_color = ListProperty(get_color_from_hex(colors['Grey']['400']))
	ripple_color = AliasProperty(_get_ripple_color,
	                             _set_ripple_color,
	                             bind=['_ripple_color'])

	def _determine_device_orientation(self, _, window_size):
		if window_size[0] > window_size[1]:
			self.device_orientation = 'landscape'
		elif window_size[1] >= window_size[0]:
			self.device_orientation = 'portrait'

	device_orientation = StringProperty('')

	def _get_standard_increment(self):
		if DEVICE_TYPE == 'mobile':
			if self.device_orientation == 'landscape':
				return dp(48)
			else:
				return dp(56)
		else:
			return dp(64)

	standard_increment = AliasProperty(_get_standard_increment,
	                                   bind=['device_orientation'])

	def _get_horizontal_margins(self):
		if DEVICE_TYPE == 'mobile':
			return dp(16)
		else:
			return dp(24)

	horizontal_margins = AliasProperty(_get_horizontal_margins)

	def on_theme_style(self, instance, value):
		if hasattr(App.get_running_app(), 'theme_cls') and \
						App.get_running_app().theme_cls == self:
			self.set_clearcolor_by_theme_style(value)

	def set_clearcolor_by_theme_style(self, theme_style):
		if theme_style == 'Light':
			Window.clearcolor = get_color_from_hex(
					colors['Light']['Background'])
		elif theme_style == 'Dark':
			Window.clearcolor = get_color_from_hex(
					colors['Dark']['Background'])

	def __init__(self, **kwargs):
		super(ThemeManager, self).__init__(**kwargs)
		self.rec_shadow = Atlas('{}rec_shadow.atlas'.format(images_path))
		self.rec_st_shadow = Atlas('{}rec_st_shadow.atlas'.format(images_path))
		self.quad_shadow = Atlas('{}quad_shadow.atlas'.format(images_path))
		self.round_shadow = Atlas('{}round_shadow.atlas'.format(images_path))
		Clock.schedule_once(lambda x: self.on_theme_style(0, self.theme_style))
		self._determine_device_orientation(None, Window.size)
		Window.bind(size=self._determine_device_orientation)


class ThemableBehavior(object):
	theme_cls = ObjectProperty(None)
	opposite_colors = BooleanProperty(False)

	def __init__(self, **kwargs):
		if self.theme_cls is not None:
			pass
		elif hasattr(App.get_running_app(), 'theme_cls'):
			self.theme_cls = App.get_running_app().theme_cls
		else:
			self.theme_cls = ThemeManager()
		super(ThemableBehavior, self).__init__(**kwargs)