import datetime
import time
import sys
import echo_serial.serial_controller as EchoSerial
import echo_db.database as EchoDB
import _thread

class Blinds:

    @staticmethod
    def handle_action(device, action, data):
        actionData = device['actions'][action]
        
        # Check if we send action too fast after last issued action
        actionNow = datetime.datetime.now()
        actionLast = device['last_used']
        lastIssued = (actionNow - actionLast).total_seconds()
        
        if lastIssued < 2.0:
            return {'status': 'failed', 'message': 'Issued action too fast after last issued action!'}, 200

        # Check if a thread is using the blinds, if so return.
        if device['status'] == "busy":
            return {'status': 'failed', 'message': 'Blinds are being controlled by Echo, Please wait till finished.'}, 200

        # Check if we issued stop command and check if we are moving
        # Stop blinds if we are moving
        if action == "stop":
            if device['status'] == "go_down" or device['status'] == "go_up":
                return Blinds.stopActiveBlinds(device, action, data)
            else:
                return {'status': 'failed', 'message': 'Blinds are not moving!'}, 200

        # Check if we are already going up or down
        # If we are, stop that action
        if device['status'] == "go_down" or device['status'] == "go_up":
            return Blinds.stopActiveBlinds(device, action, data)
        
        # If we are requesting specific preset
        if action == "preset":
            selected_preset = data

            if selected_preset == {}:
                return {'status': 'failed', 'message': 'Please select a preset!'}, 200

            if selected_preset not in device['presets']:
                return {'status': 'failed', 'message': 'Preset does not exist!'}, 200

            # Update Database
            collection = EchoDB.EchoDB.database['Devices']
            collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'status': 'busy' }})

            # Start thread because this action has waiting functions
            _thread.start_new_thread(Blinds.handleBlindsPreset, ("Main Serial Thread", 2, device, selected_preset))
            return {'status': 'success', 'message': actionData['message']}, 200
        
        # If we are requesting action
        if action == "up" or action == "down":
            # Send Serial Command
            EchoSerial.EchoSerial.send_commmand(device, action)

            # Update Database
            collection = EchoDB.EchoDB.database['Devices']
            collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'status': 'go_' + action }})

            return {'status': 'success', 'message': actionData['message']}, 200
        
        # If we are requesting to set automatic time
        if action == "set_automatic_time":
            selected_auto_time = data

            if selected_auto_time == {}:
                return {'status': 'failed', 'message': 'Please select a time!'}, 200

            if selected_auto_time == "--:--":
                # Update Database
                collection = EchoDB.EchoDB.database['Devices']
                collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'automatic_open': False, 'automatic_open_time': '--:--' }})
            else:
                # Update Database
                collection = EchoDB.EchoDB.database['Devices']
                collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'automatic_open': True, 'automatic_open_time': selected_auto_time }})
            

            return {'status': 'success', 'message': actionData['message']}, 200


    
    @staticmethod
    def stopActiveBlinds(device, action, data):
        if device['status'] == "go_down":
            EchoSerial.EchoSerial.send_commmand(device, "down")
            # Update Database
            collection = EchoDB.EchoDB.database['Devices']
            collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'status': 'custom' }})
            return {'status': 'success', 'message': 'Stopped blinds.'}, 200

        if device['status'] == "go_up":
            EchoSerial.EchoSerial.send_commmand(device, "up")
            # Update Database
            collection = EchoDB.EchoDB.database['Devices']
            collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'status': 'custom' }})
            return {'status': 'success', 'message': 'Stopped blinds.'}, 200


    @staticmethod
    def handleBlindsPreset(threadname, delay, device, preset):
        print('Started Blinds Preset Thread!')
        presetData = device['presets'][preset]

        # Check if we are already in preset position
        if device['status'] == "preset":
            if device['current_preset'] == preset:
                # Update Database
                collection = EchoDB.EchoDB.database['Devices']
                collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'status': 'custom' }})
                print('Exiting Blinds Preset Thread!')
                sys.exit()

        # If custom goto open position
        if device['status'] == "custom":
            Blinds.setBlindsOpen(device)
        
        # If device is already in preset position, check if we need to go to open position first
        # Or if we can skip that
        if device['status'] == "preset":
            if device['current_preset'] != "open":
                Blinds.setBlindsOpen(device)

        if preset == "closed_ventilated":
            # Go down for 11 seconds
            EchoSerial.EchoSerial.send_commmand(device, 'down')
            time.sleep(17)
            EchoSerial.EchoSerial.send_commmand(device, 'down')

        if preset == "open_ventilated":
            # Go down for 11 seconds
            EchoSerial.EchoSerial.send_commmand(device, 'down')
            time.sleep(11)
            EchoSerial.EchoSerial.send_commmand(device, 'down')

        if preset == "open":
            # We already went to open position, no need to do it again
            pass
        
        if preset == "closed":
            EchoSerial.EchoSerial.send_commmand(device, 'down')
            time.sleep(19)
            EchoSerial.EchoSerial.send_commmand(device, 'down')

        # Update Database
        collection = EchoDB.EchoDB.database['Devices']
        collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'status': 'preset', 'current_preset': preset }})
        print('Exiting Blinds Preset Thread!')

    @staticmethod
    def setBlindsOpen(device):
        EchoSerial.EchoSerial.send_commmand(device, 'up')
        time.sleep(25)
        EchoSerial.EchoSerial.send_commmand(device, 'up')
        time.sleep(2)
