import ast
import json
import requests
import numpy as np
import base64
import struct
from struct import pack
import time
from django.contrib import messages
from django.db import models
from django.urls import reverse
from django.core.validators import MinValueValidator, MaxValueValidator

from apps.main.models import Configuration

AXIS_VALUE = (
        ('AZI', 'azimuth'),
        ('ELE', 'elevation')
    )

class PedestalConfiguration(Configuration):

    axis = models.CharField(
        verbose_name='Axis',
        max_length=3,
        choices=AXIS_VALUE,
        null=False,
        blank=False
    )

    speed = models.FloatField(
        verbose_name='Speed',
        validators=[MinValueValidator(-20), MaxValueValidator(20)],
        blank=False, 
        null=False
    )

    table = models.CharField(
        verbose_name="Table",
        max_length=100,
        default='',
        blank=False, 
        null=False
    )

    class Meta:
        db_table = 'pedestal_configurations'
    
    def __str__(self):
        return self.label

    def get_absolute_url_plot(self):
        return reverse('url_plot_pedestal_pulses', args=[str(self.id)])

    def request(self, cmd, method='get', **kwargs):

        req = getattr(requests, method)(self.device.url(cmd), **kwargs)
        payload = req.json()

        return payload

    def status_device(self):

        try:
            self.device.status = 0
            payload = self.request('status')
            if payload['status']=='enable':
                self.device.status = 3
            elif payload['status']=='disable':
                self.device.status = 2
            else:
                self.device.status = 1
                self.device.save()
                self.message = 'Pedestal status: {}'.format(payload['status'])
                return False
        except Exception as e:
            if 'No route to host' not in str(e):
                self.device.status = 4
            self.device.save()
            self.message = 'Pedestal status: {}'.format(str(e))
            return False

        self.device.save()
        return True

    def reset_device(self):

        try:
            payload = self.request('reset', 'post')
            if payload['reset']=='ok':
                self.message = 'Pedestal restarted OK'
                self.device.status = 2
                self.device.save()
            else:
                self.message = 'Pedestal restart fail'
                self.device.status = 4
                self.device.save()
        except Exception as e:
            self.message = 'Pedestal reset: {}'.format(str(e))
            return False

        return True

    def stop_device(self):

        try:
            command = self.device.url() + "stop"
            r = requests.get(command)
            if r:
                self.device.status = 4
                self.device.save()
                self.message = 'Pedestal stopped'
            else:
                self.device.status = 4
                self.device.save()
                return False
        except Exception as e:
            if 'No route to host' not in str(e):
                self.device.status = 4
            else:
                self.device.status = 0
            self.message = 'Pedestal stop: {}'.format(str(e))
            self.device.save()
            return False

        return True

    def start_device(self):
        print("Entró al start")
        try:
            pedestal = PedestalConfiguration.objects.get(pk=self)
            pedestal_axis = pedestal.get_axis_display()
            print(pedestal)
            print(pedestal_axis)
            table = pedestal.table
            print(table)
            li = list(table.split(", "))
            print(li)
            list_of_floats = []
            for item in li:
                list_of_floats.append(float(item))
            print(list_of_floats)
            byte_table = []
            for x in list_of_floats:
                temp = bytearray(struct.pack("f", x))
                byte_table.append(temp[3])
                byte_table.append(temp[2])
                byte_table.append(temp[1])
                byte_table.append(temp[0])
            print(byte_table)
            coded_table = base64.urlsafe_b64encode(bytes(byte_table))
            coded_table_ascii = coded_table.decode('ascii')
            print(coded_table_ascii)
            data = {'axis': pedestal_axis, 'speed': pedestal.speed, 'table': coded_table_ascii}
            print(data)
            json_data = json.dumps(data)
            print(json_data)
            first_position = table[0]

            if pedestal.axis=='azimuth':
                json_az = json.dumps({"axis": 'azimuth', "position": 0.0})
                json_el = json.dumps({"axis": 'elevation', "position": first_position})
            else:
                json_az = json.dumps({"axis": 'azimuth', "position": first_position})
                json_el = json.dumps({"axis": 'elevation', "position": 0.0})

            base64_table = base64.urlsafe_b64encode(json_data.encode('ascii'))
            base64_az = base64.urlsafe_b64encode(json_az.encode('ascii'))
            base64_el = base64.urlsafe_b64encode(json_el.encode('ascii'))
            
            table_url = self.device.url() + "table?params="
            az_url = self.device.url() + "position?params="
            el_url = self.device.url() + "position?params="

            
            complete_url = table_url + base64_table.decode('ascii')

            az_url = az_url + base64_az.decode('ascii')
            el_url = el_url + base64_el.decode('ascii')
            print(complete_url)
            print(az_url)
            print(el_url)
            r = requests.get(az_url)
            r = requests.get(el_url)
            #time.sleep(10)
            r = requests.get(complete_url)
            if r:
                self.device.status = 3
                self.device.save()
                self.message = 'Pedestal configured and started'
            else:
                return False
        except Exception as e:
            if 'No route to host' not in str(e):
                self.device.status = 4
            else:
                self.device.status = 0
            self.message = 'Pedestal start: {}'.format(str(e))
            self.device.save()
            return False

        return True

    #def write_device(self, raw=False):        

        if not raw:
            clock = RCClock.objects.get(rc_configuration=self)
            print(clock)
            if clock.mode:
                data = {'default': clock.frequency}
            else:
                data = {'manual': [clock.multiplier, clock.divisor, clock.reference]}
            payload = self.request('setfreq', 'post', data=json.dumps(data))
            print(payload)
            if payload['command'] != 'ok':
                self.message = 'Pedestal write: {}'.format(payload['command'])
            else:
                self.message = payload['programming']
                if payload['programming'] == 'fail':
                    self.message = 'Pedestal write: error programming CGS chip'
        
        values = []
        for pulse, delay in zip(self.get_pulses(), self.get_delays()):
            while delay>65536:
                values.append((pulse, 65535))
                delay -= 65536
            values.append((pulse, delay-1))
        data = bytearray()
        #reset
        data.extend((128, 0))
        #disable
        data.extend((129, 0))
        #SW switch
        if self.control_sw:
            data.extend((130, 2))
        else:
            data.extend((130, 0))
        #divider
        data.extend((131, self.clock_divider-1))
        #enable writing
        data.extend((139, 62))

        last = 0
        for tup in values:
            vals = pack('<HH', last^tup[0], tup[1])
            last = tup[0]
            data.extend((133, vals[1], 132, vals[0], 133, vals[3], 132, vals[2]))

        #enable
        data.extend((129, 1))

        if raw:
            return b64encode(data)

        try:
            payload = self.request('stop', 'post')
            payload = self.request('reset', 'post')
            #payload = self.request('divider', 'post', data={'divider': self.clock_divider-1})
            #payload = self.request('write', 'post', data=b64encode(bytearray((139, 62))), timeout=20)
            n = len(data)
            x = 0
            #while x < n:
            payload = self.request('write', 'post', data=b64encode(data))
            #    x += 1024
            
            if payload['write']=='ok':
                self.device.status = 3
                self.device.save()
                self.message = 'Pedestal configured and started'
            else:
                self.device.status = 1
                self.device.save()
                self.message = 'Pedestal write: {}'.format(payload['write'])
                return False

            #payload = self.request('start', 'post')

        except Exception as e:
            if 'No route to host' not in str(e):
                self.device.status = 4
            else:
                self.device.status = 0
            self.message = 'Pedestal write: {}'.format(str(e))
            self.device.save()
            return False

        return True


    def get_absolute_url_import(self):
        return reverse('url_import_pedestal_conf', args=[str(self.id)])