#
# Copyright 2019 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
# These materials are licensed under the Amazon Software License in connection with the Alexa Gadgets Program.
# The Agreement is available at https://aws.amazon.com/asl/.
# See the Agreement for the specific terms and conditions of the Agreement.
# Capitalized terms not defined in this file have the meanings given to them in the Agreement.
#

import json
import logging
import sys
import threading
import time
from enum import Enum
from datetime import datetime
import dateutil.parser
import traceback
import webcolors

import board
import neopixel

from agt import AlexaGadget
from smart_mirror import SmartMirror
from parameter_store_helper import fetch_and_store_parameters, get_parameters, SmartMirrorConfig

logging.basicConfig(stream=sys.stdout, level=logging.INFO)
logger = logging.getLogger(__name__)


class Actions(Enum):
    Off = 0
    Rainbow = 1
    Breathe = 2
    ShowColor = 3


class SmartMirrorGadget(AlexaGadget):
    """
    An Alexa Gadget for your simple smart mirror.
    """
    def __init__(self):
        super().__init__()

        self.config = self.get_parameters()
        self.smart_mirror = SmartMirror(self.config)

        #This sets what action is starte when the mirror starts
        self.defaultAction = Actions.Rainbow
        self.currentAction = self.defaultAction
        self.lastAction = self.defaultAction

        # Boolean that tells the loop if it should execute actions or not - default is True which means that the configured default action (self.defaultAction)
        # will be used
        self.keep_cycling = True

        #default options for show color as a reference
        self.showColorOptions = {
            'color': webcolors.name_to_rgb('yellow')
        }

        # Setup a lock to be used for avoiding race conditions
        # during color animation state updates
        self.lock = threading.Lock()
        self.loop_thread = threading.Thread(target=self.loop)
        self.loop_thread.start()

    def get_parameters(self):
        """
        Gets the parameters from parameter store
        """
        try:
            fetch_and_store_parameters()
            parameters = get_parameters()
            return SmartMirrorConfig(parameters)
        except:
            return SmartMirrorConfig({})

    def startAction(self, action):    
        """
        Call this function to start a specific action
        """
        logger.info(f'Starting Action {action}')
        self.lock.acquire()
        self.lastAction = self.currentAction
        self.currentAction = action
        self.keep_cycling = True
        self.lock.release()

    def stopAction(self):
        """
        Call this action to end the current action - turn all LEDs off
        """
        self.lock.acquire()
        self.lastAction = Actions.Off
        self.currentAction = Actions.Off
        self.keep_cycling = False
        self.lock.release()

    def loop(self):
        """
        Main function of this class. This is an endless loop running in a separate thread. It will check what action to run on each iteration.
        """
        while True:
            # Check if anything should be visualized
            if self.keep_cycling:
                logger.info('Something is on')
                try:
                    if self.currentAction == Actions.Off:
                        time.sleep(0.1)
                    if self.currentAction == Actions.Rainbow:
                        self.smart_mirror.rainbow_cycle(0.001)
                    if self.currentAction == Actions.Breathe:
                        self.smart_mirror.breathe()
                    if self.currentAction == Actions.ShowColor:
                        self.smart_mirror.showColor(
                            self.showColorOptions['color'])
                except Exception as e:
                    logger.info(f'Error in loop: {e}')
                    logger.error(f'Stack: {traceback.format_exc()}')
                    time.sleep(0.1)
            else:
                logger.info('Nothing is on')
                self.smart_mirror.reset()
                time.sleep(0.1)

    def on_alexa_gadget_statelistener_stateupdate(self, directive):
        """
        This will trigger when your connected Alexa device changes state. Here we listening for your Alexa to react to you saying "Alexa..." or "Echo..."
        """
        for state in directive.payload.states:
            if state.name == 'wakeword':
                if state.value == 'active':
                    logger.info('Wake word active')
                    self.showColorOptions['color'] = webcolors.name_to_rgb('yellow')
                    self.startAction(Actions.ShowColor)
                elif state.value == 'cleared':
                    logger.info('Wake word cleared')
                    self.startAction(self.lastAction)

    # this matches the namespace that the skill adds in the payload (see lambda_function.py): (namespace='Custom.SmartMirror', name='Rainbow'),
    def on_custom_smartmirror_rainbow(self, directive):
        """
        Handles Custom.SmartMirror.Rainbow directive
        """

        logger.info('show rainbow directive called')

        self.startAction(Actions.Rainbow)

    def on_custom_smartmirror_stopled(self, directive):
        """
        Handles Custom.ColorCyclerGadget.StopLED directive sent from skill
        by stopping the LED animations
        """
        logger.info('StopLED directive received: Turning off LED')

        self.stopAction()

    def reset(self):
        """
        Turn off all LEDs by calling the reset function
        """
        try:
            self.smart_mirror.reset()
        except:
            print(f'failed to reset')


if __name__ == '__main__':
    gadget = SmartMirrorGadget()
    try:
        gadget.main()
    finally:
        gadget.reset()