#from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
#from datetime import datetime
from flask import current_app, url_for
from flask_login import UserMixin
from sqlalchemy.sql import func
from sqlalchemy.dialects import postgresql, sqlite
from webinterface import db, login_manager

@login_manager.user_loader
def load_user(user_id):
    return Persona.query.filter(Persona.rut==user_id).one_or_none()

class Identidad(db.Model):
    __tablename__ = 'identidades'
    __table_args__ = { 'schema': 'usuarios' }
    __bind_key__ = 'system'

    id = db.Column(db.BigInteger(), primary_key=True, autoincrement=True)

    login   = db.Column(db.String(50), unique=True, nullable=False)
    alias   = db.Column(db.String(50))

    creado  = db.Column(db.DateTime(timezone=True), server_default=func.now())
    modificado = db.Column(db.DateTime(timezone=True), server_onupdate=func.now())

    sesiones = db.relationship('Sesion', back_populates='identidad', lazy=True)
    ubicaciones   = db.relationship('Ubicacion', back_populates='identidad', lazy=True)

    tipo    = db.Column(db.String(20))
    __mapper_args__ = {
        'polymorphic_identity':'Identidad',
        'polymorphic_on':tipo

        }

class Cuenta(Identidad):
    __tablename__ = 'cuentas'
    __table_args__ = { 'schema': 'usuarios' }
    __bind_key__ = 'system'

    id = db.Column(db.BigInteger(), db.ForeignKey('usuarios.identidades.id'), primary_key=True)

    clave   = db.Column(db.String(60), nullable=False)
    sysadmin   = db.Column(db.Boolean, default=0)
    ultimoacceso = db.Column(db.DateTime(timezone=True))

    __mapper_args__ = {
        'polymorphic_identity':'Cuenta'
        }

    correos        = db.relationship('Correo', back_populates='cuenta', lazy=True)

    def set_default(self, correo):
        for item in self.correos:
            if correo == item:
                correo.default = True
            else:
                correo.default = False

    @property
    def correodefecto(self):
        last = None
        for item in self.correos:
            if item.default == True:
                return item
            elif last is None:
                last = item

        return last

    @correodefecto.setter
    def correodefecto(self, correo):
        if correo.cuenta != self:
            pass

        for item in self.correos:
            if item == correo:
                item.default = True
            else:
                item.default = False

class Persona(Cuenta,UserMixin):
    __tablename__  = 'personas'
    __table_args__ = { 'schema': 'usuarios' }
    __bind_key__ = 'system'

    id = db.Column(db.BigInteger(), db.ForeignKey('usuarios.cuentas.id'), primary_key=True)

    nombres        = db.Column(db.String(100), nullable=False)
    apellidop      = db.Column(db.String(100), nullable=False)
    apellidom      = db.Column(db.String(100))

    rut            = db.Column(db.String(20), unique=True, nullable=False)
    telefono       = db.Column(db.String(20), nullable=True)
    foto           = db.Column(db.String(50), nullable=False, default='default.jpg')

    __mapper_args__ = {
    'polymorphic_identity':'Persona'
    }
    def get_id(self):
        return self.rut

    @property
    def nombrecompleto(self):
        if self.apellidom is not None:
            return u"{} {} {}.".format(self.nombres.partition(' ')[0], self.apellidop, self.apellidom[0])
        else:
            return u"{} {}.".format(self.nombres.partition(' ')[0], self.apellidop)
    @property
    def safe_nombrecompleto(self):
        return "{}".format(self.nombrecompleto.encode('utf-8'))
    @property
    def ascii_nombrecompleto(self):
        return unidecode.unidecode(self.nombrecompleto)

    def is_in(self, comision=0):
        return True

    @property
    def sidebar_menu(self):
        import json
        from .gestion import AccesoGestion
        # Primer menu, de carrera Visión de jefe de carrera
        amGestion = AccesoGestion()

        if amGestion.in_gestion():
            cat = u"Gobernanza"
            links = []

            for modulo in amGestion.get_nodes():
                links.append((modulo.nodobase.nombre, modulo.nodobase.tipo, modulo.nodobase.descripcion, url_for('gestion.main', uri=modulo.uri) ))

            if amGestion.is_admin():
                links.append((u'Comisiones','users-cog','gestion.manager', url_for('gestion.manager')))

            if amGestion.sysadmin:
                links.append((u'Módulos','boxes','gestion.modulos', url_for("gestion.modulos")))

            if len(links) > 0:
                yield(100, u"Dashboard", "tasks", cat, links)

        cat = "Información Oficial" #
        links = [
                ("GTFS Estático", "map-marked-alt", "main.home", url_for("main.home")),
                ("GTFS Dinamico", "satellite-dish", "main.home", url_for("main.home")),
                ("Paradas", "store", "main.home", url_for("main.home")),
                ("Rutas", "bus-alt", "main.home", url_for("main.home")),
                ("Conductores", "user-alt", "main.home", url_for("main.home")),
                ("Vehículo", "shuttle-van", "main.home", url_for("main.home")),
                ("En construcción", "tools", "main.home", url_for("main.home")),
#                ("Críticos", "user-injured", "main.home"),
                ]
        yield(200, "Gran Concepción", "city", cat, links)

class Correo(db.Model):
    __tablename__ = 'correos'
    __table_args__ = { 'schema': 'usuarios' }
    __bind_key__ = 'system'

    id = db.Column(db.Integer, primary_key=True)
    correo = db.Column(db.String(100), unique=True, nullable=False)

    cuentaid = db.Column(db.BigInteger(), db.ForeignKey('usuarios.cuentas.id'), nullable=False)
    cuenta = db.relationship('Cuenta', back_populates='correos')
    default   = db.Column(db.Boolean, default=0)


class Sesion(db.Model):
    __tablename__ = 'sesiones'
    __table_args__ = { 'schema': 'registros' }
    __bind_key__ = 'system'

    id          = db.Column(db.BigInteger(), primary_key=True)

    identidadid = db.Column(db.BigInteger(), db.ForeignKey('usuarios.identidades.id'), nullable=False)
    identidad   = db.relationship('Identidad', back_populates='sesiones')

    dispositivoid = db.Column(db.Integer, db.ForeignKey('registros.dispositivos.id'), nullable=False)
    dispositivo = db.relationship('Dispositivo')

    conexiones   = db.relationship('Conexion')

    iniciada    = db.Column(db.DateTime(timezone=True), server_default=func.now())
    ultimo      = db.Column(db.DateTime(timezone=True), server_onupdate=func.now())

    def __repr__(self):
        return u"Session ('{}','{}','{}')".format(self.identidad.login, self.ipaddr.ipaddr, self.useragent.parsed_ua)

class Conexion(db.Model):
    __tablename__ = 'conexiones'
    __table_args__ = { 'schema': 'registros' }
    __bind_key__ = 'system'

    id       = db.Column(db.BigInteger(), primary_key=True)

    ipaddrid    = db.Column(db.Integer, db.ForeignKey('registros.ipaddrs.id'), nullable=False)
    ipaddr      = db.relationship('Ipaddr')

    sesionid = db.Column(db.Integer, db.ForeignKey('registros.sesiones.id'), nullable=False)
    sesion   = db.relationship('Sesion', back_populates='conexiones', lazy=True)

    iniciada    = db.Column(db.DateTime(timezone=True), server_default=func.now())
    ultimo      = db.Column(db.DateTime(timezone=True), server_onupdate=func.now())

    __table_args__ = (db.UniqueConstraint('ipaddrid', 'sesionid', name='_una_ip_sesion_uc'),{ 'schema': 'registros' })

class Ubicacion(db.Model):
    __tablename__ = 'ubicaciones'
    __table_args__ = { 'schema': 'registros' }
    __bind_key__ = 'system'

    id       = db.Column(db.BigInteger(), primary_key=True)

    ipaddrid    = db.Column(db.Integer, db.ForeignKey('registros.ipaddrs.id'), nullable=False)
    ipaddr      = db.relationship('Ipaddr')

    identidadid = db.Column(db.Integer, db.ForeignKey('usuarios.identidades.id'), nullable=False)
    identidad   = db.relationship('Identidad', back_populates='ubicaciones', lazy=True)

    descripcion = db.Column(db.String(200), nullable=True)

    iniciada    = db.Column(db.DateTime(timezone=True), server_default=func.now())
    ultimo      = db.Column(db.DateTime(timezone=True), server_onupdate=func.now())

    __table_args__ = (db.UniqueConstraint('ipaddrid', 'identidadid', name='_una_ip_identidad_uc'),{ 'schema': 'registros' })

class Ipaddr(db.Model):
    __tablename__ = 'ipaddrs'
    __table_args__ = { 'schema': 'registros' }
    __bind_key__ = 'system'

    id       = db.Column(db.Integer, primary_key=True)

    ipaddr   = db.Column(db.String(15).with_variant(postgresql.INET(), 'postgresql'), unique=True, nullable=False)
    hostname = db.Column(db.String(100), nullable=True)

    def __repr__(self):
        return "IpAddr('{}','{}')".format(self.ipaddr, self.hostname)

class Dispositivo(db.Model):
    __tablename__ = 'dispositivos'
    __table_args__ = { 'schema': 'registros' }
    __bind_key__ = 'system'

    id = db.Column(db.Integer, primary_key=True)
    useragent = db.Column(db.String(1024), unique=True, nullable=False)
    parsed_ua = db.Column(db.String(150))
    dev = db.Column(db.String(50))
    os = db.Column(db.String(50))
    browser = db.Column(db.String(50))

    def __repr__(self):
        return "Useragent('{}')".format(self.parsed_ua)

class Ruta(db.Model):
    __tablename__ = 'rutas'
    __table_args__ = { 'schema': 'registros' }
    __bind_key__ = 'system'

    id       = db.Column(db.Integer, primary_key=True)
    ruta   = db.Column(db.String(100), unique=True, nullable=False)

    def __repr__(self):
        return "Url('{}')".format(self.ruta)

class Registro(db.Model):
    __tablename__ = 'registros'
    __table_args__ = { 'schema': 'registros' }
    __bind_key__ = 'system'

    id          = db.Column(db.BigInteger(), primary_key=True)

    sitioid      = db.Column(db.Integer, db.ForeignKey('registros.sitios.id'), nullable=False)
    sitio        = db.relationship('Sitio')

    rutaid      = db.Column(db.Integer, db.ForeignKey('registros.rutas.id'), nullable=False)
    ruta        = db.relationship('Ruta')

    sesionid    = db.Column(db.BigInteger().with_variant(sqlite.INTEGER(), 'sqlite'), db.ForeignKey('registros.sesiones.id'), nullable=False)
    sesion      = db.relationship('Sesion')

    ipaddrid    = db.Column(db.Integer, db.ForeignKey('registros.ipaddrs.id'), nullable=False)
    ipaddr      = db.relationship('Ipaddr')

    tamano      = db.Column(db.Integer)
    creado      = db.Column(db.DateTime, server_default=func.now())

    def __repr__(self):
        return "Registro('{}')".format(self.ruta.ruta)

class Sitio(db.Model):
    __tablename__ = 'sitios'
    __table_args__ = { 'schema': 'registros' }
    __bind_key__ = 'system'

    id          = db.Column(db.Integer, primary_key=True)
    sitio       = db.Column(db.String(100), unique=True, nullable=False)
