# coding: utf-8
#from datetime import datetime
from sqlalchemy.sql import func
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.dialects import sqlite

from webinterface import db
from flask_login import current_user
from flask import current_app, g
import datetime
import unidecode
from webinterface.models.system import Persona
from webinterface.models.documentos import Documento


class Comision(db.Model):
	__tablename__   = 'comisiones'
	__table_args__ = { 'schema': 'gestion' }
	__bind_key__ = 'system'

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

	nombre          = db.Column(db.String(100), nullable=False)
	descripcion     = db.Column(db.String(100))
	creado          = db.Column(db.Integer, db.ForeignKey('gestion.comisiones.id'), nullable=False)
	logo            = db.Column(UUID(as_uuid=True), nullable=True, autoincrement=False)
	titulo          = db.Column(UUID(as_uuid=True), nullable=True, autoincrement=False)

	__table_args__  = (db.UniqueConstraint('nombre', 'creado', name='nodupesComisiones'), { 'schema': 'gestion' })

	@property
	def supervisor(self):
		return Comision.query.filter(Comision.id==self.creado).one_or_none()

	@property
	def quorum(self):
		miembro = Miembro.query.filter(Miembro.comisionid==self.id).count()
		if miembro == 0:
			return False
		else:
			return miembro

	@property
	def miembros(self):
		for miembro in Miembro.query.filter(Miembro.comisionid==self.id).all():
			yield miembro.persona

	def mvector(self):
		vector = []
		for persona in self.miembros:
			vector.append(persona.id)

		return vector


class Miembro(db.Model):
	__tablename__  = 'miembros'
	__table_args__ = { 'schema': 'gestion' }
	__bind_key__ = 'system'

	id             = db.Column(db.Integer, primary_key=True)
	personaid      = db.Column(db.BigInteger, db.ForeignKey('usuarios.personas.id'))
	comisionid     = db.Column(db.Integer, db.ForeignKey('gestion.comisiones.id'))

	persona        = db.relationship('Persona')
	comision       = db.relationship('Comision')

class Objetivo(db.Model):
	__tablename__   = 'objetivos'
	__table_args__ = { 'schema': 'gestion' }
	__bind_key__ = 'system'

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

	tipo            = db.Column(db.String(100), nullable=False, default=u'Estratégico')
	nombre          = db.Column(db.String(200), nullable=False)
	descripcion     = db.Column(db.Text)

	parentid        = db.Column(db.Integer, db.ForeignKey('gestion.objetivos.id'), nullable=False)
	responsableid   = db.Column(db.Integer, db.ForeignKey('gestion.comisiones.id'), nullable=False)
	invitadosid     = db.Column(db.Integer, db.ForeignKey('gestion.comisiones.id'), nullable=True)

	#    indicadores     = db.relationship('Avance', back_populates="objetivo", order_by='Accion.id.desc()')
	actas     		= db.relationship('Acta', back_populates="objetivo", order_by='Acta.secuencia.desc()')
	actividades     = db.relationship('Accion', back_populates="objetivo", order_by='Accion.fecha.desc()')
	responsable     = db.relationship('Comision', foreign_keys=[responsableid])
	invitados       = db.relationship('Comision', foreign_keys=[invitadosid])

	estado          = db.Column(db.SmallInteger, default=100)

	## registros de auditoria
	creado			= db.Column(db.DateTime, default=func.now())
	creadopor		= db.Column(db.Integer, db.ForeignKey('usuarios.personas.id'), nullable=True)
	modificado      = db.Column(db.DateTime, default=func.now(), onupdate=func.now())
	modificadopor	= db.Column(db.Integer, db.ForeignKey('usuarios.personas.id'), nullable=True)

	@property
	def actasr(self):
		for item in Acta.query.filter(Acta.objetivoid==self.id).order_by(Acta.secuencia.asc()).all():
			yield item

	@property
	def sub_HDS(self):
		return round(self.sub_horas/26,2)

	@property
	def modulo(self):
		return ModuloGestion.query.filter(ModuloGestion.basenodeid==self.get_root().parentid).one_or_none()

	@property
	def modulo_raw(self):
		return ModuloGestion.query.filter(ModuloGestion.basenodeid==self.id).one_or_none()

	@property
	def indicadores(self):
		for item in Avance.query.filter(Avance.objetivoid==self.id).order_by(Avance.id.asc()).all():
			yield item

	@property
	def iactividades(self):
		for item in Accion.query.filter(Accion.objetivoid==self.id).order_by(Accion.fecha.asc()).all():
			yield item

	@property
	def hijos(self):
		for item in Objetivo.query.filter(Objetivo.parentid==self.id, Objetivo.estado<100).order_by(Objetivo.id.asc()).all():
			yield item
		for item in Objetivo.query.filter(Objetivo.parentid==self.id, Objetivo.estado>=100).order_by(Objetivo.id.asc()).all():
			yield item

	@property
	def padre(self):
		return Objetivo.query.get(self.parentid)

	@property
	def icon_class(self):
		return self.get_root().tipo

	@property
	def sub_actividades(self):
		i = 0
		for item in self.hijos:
			i += item.sub_actividades
		for item in self.actividades:
			i += 1
		return i

	@property
	def sub_horas(self):
		h = 0
		for item in self.hijos:
			h += item.sub_horas
		for item in self.actividades:
			h += item.dedicacion
		for item in self.actas:
			h += item.dedicacion

		return h
	@property
	def sub_HDS(self):
		return round(self.sub_horas/26,2)

	@property
	def sub_avanceNormalizado(self):
		base = 0
		numBase = 0

		for item in self.hijos:
			base += item.sub_avanceNormalizado
			numBase += 1

		for item in self.indicadores:
			base += item.avanceNormalizado
			numBase += 1

		return base/numBase if numBase else 0

	@property
	def sub_avance(self):
		return round(100*self.sub_avanceNormalizado)

	def is_root(self):
		if self.padre.parentid == 1:
			return True
		else:
			return False

	def get_root(self):

		node = self
		while node.padre.parentid > 1:
			node = node.padre

		return node

	@property
	def comisiones_validas(self):
		node = self.get_root()

		yield node.responsable

		for comision in Comision.query.filter(Comision.creado == node.responsableid).all():
			yield comision

	@property
	def miembros_responsables(self):
		for miembro in self.responsable.miembros:
			yield miembro

	@property
	def miembros_habilitados(self):
		vistos = []
		for miembro in self.responsable.miembros:
			if miembro not in vistos:
				vistos.append(miembro)
				yield miembro
		if self.invitados is not None:
			for miembro in self.invitados.miembros:
				if miembro not in vistos:
					vistos.append(miembro)
					yield miembro

	@property
	def archivado(self):
		if self.estado < 100:
			return False
		else:
			return True

	def lineage(self):
		ancestrys=[]

		node = self.padre
		while node.parentid > 1:
			ancestrys.append(node)
			node = node.padre

		for node in reversed(ancestrys):
			yield node

	def get_comisiones(self, lvl=1, archived=False):

		if self.invitadosid is None:
			comisiones = [self.responsableid]
		else:
			comisiones = [self.responsableid, self.invitadosid]
		if lvl > 0:
			lvl = lvl - 1
			for objetivo in self.hijos:
				if objetivo.estado is None or objetivo.estado<100 or archived:
					comisiones = comisiones + objetivo.get_comisiones(lvl=lvl, archived=archived)

		return comisiones

	def visible(self, lvl=5, archived=False):
		comisiones = self.get_comisiones(lvl=lvl, archived=archived)
		if len(comisiones)>0:
			comisiones = list(set(comisiones))
			try:
				comisiones.remove(1)
			except:
				pass
			existe = Miembro.query.filter(Miembro.comisionid.in_(comisiones), Miembro.personaid==current_user.id).first()
			if existe is None:
	#				current_app.logger.debug('[No-Visble] Nodo {}: {} ({})'.format(self.nombre, current_user.login, comisiones))
				return False
			else:
	#				current_app.logger.debug('[Visible] Nodo {}: {} ({})'.format(self.nombre, current_user.login, comisiones))
				return True
		else:
			return False

	@property
	def is_manager(self):


		comisiones =  list(set( [ self.responsableid, self.padre.responsableid ] ))

		existe = Miembro.query.filter(Miembro.comisionid.in_(comisiones), Miembro.personaid==current_user.id).first()
		if existe is None:
			return False
		else:
			return True


class Avance(db.Model):
	__tablename__   = 'indicadores'
	__table_args__ = { 'schema': 'gestion' }
	__bind_key__ = 'system'

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

	objetivoid      = db.Column(db.Integer, db.ForeignKey('gestion.objetivos.id'))

	nombre          = db.Column(db.String(200), nullable=False)

	inicial         = db.Column(db.Integer, default=0)
	valor           = db.Column(db.Integer)
	meta            = db.Column(db.Integer, default=100)
	ponderacion     = db.Column(db.Integer, default=1)

	objetivo        = db.relationship('Objetivo')

	@property
	def progreso(self):
	    if self.valor>self.inicial:
	        return self.valor-self.inicial
	    else:
	        return 0
	@property
	def previo(self):
	    return int(100.0*self.inicial/self.meta)

	@property
	def avanceNormalizado(self):
	    return min(self.progreso/(self.meta-self.inicial), 1)

	@property
	def avance(self):
	    return int(100.0*self.progreso/self.meta)

class Acta(db.Model):
	__tablename__   = 'actas'
	__table_args__ = { 'schema': 'gestion' }
	__bind_key__ = 'system'

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

	objetivoid      = db.Column(db.Integer, db.ForeignKey('gestion.objetivos.id'))
	secuencia       = db.Column(db.Integer)

	horaini         = db.Column(db.DateTime)
	horafin         = db.Column(db.DateTime)

	lugar           = db.Column(db.String, nullable=False)

	temas           = db.Column(db.Text)
	desarrollo      = db.Column(db.Text)
	acuerdos        = db.Column(db.Text)

	objetivo        = db.relationship('Objetivo', back_populates='actas')
	miembros        = db.relationship('MiembrosAsistentes', back_populates='acta')
	invitados       = db.relationship('InvitadosAsistentes', back_populates='acta')
	anexos      	= db.relationship('AnexosActa', back_populates='acta')

	## registros de auditoria
	creado			= db.Column(db.DateTime, default=func.now())
	creadopor		= db.Column(db.Integer, db.ForeignKey('usuarios.personas.id'), nullable=True)
	modificado      = db.Column(db.DateTime, default=func.now(), onupdate=func.now())
	modificadopor	= db.Column(db.Integer, db.ForeignKey('usuarios.personas.id'), nullable=True)

	@property
	def documentos(self):
		for evidencia in self.anexos:
			yield evidencia.documento

	@property
	def dedicacion(self):
		import datetime
		now = datetime.datetime.now()
		if self.horaini < now and self.horafin < now:
			timedelta = self.horafin - self.horaini
			secondsdelta = timedelta.total_seconds()
			horasdelta = secondsdelta / 3600.0
		else:
			horasdelta = 0

		return horasdelta

	@property
	def correosasistentes(self):
		asistentes = []
		for persona in self.miembros:
			asistentes.append( (persona.persona.nombrecompleto, persona.persona.correodefecto.correo) )
		for persona in self.invitados:
			asistentes.append( (persona.nombre, persona.correo) )
		return asistentes

	@property
	def asistentes(self):
		asistentes = []
		for persona in self.miembros:
			asistentes.append( persona.persona.nombrecompleto )
		for persona in self.invitados:
			asistentes.append( persona.nombre )
		return asistentes

	@property
	def txtasistentes(self):
		asistentes = []
		for persona in self.miembros:
			asistentes.append( persona.persona.nombrecompleto )
		for persona in self.invitados:
			asistentes.append( u"{} ({})".format(persona.nombre, persona.correo) )

		return ", ".join(asistentes)

	@property
	def miembrosid(self):
		listado = []
		for persona in self.miembros:
			listado.append( persona.personaid )
		return listado

	@property
	def invitadostextarea(self):
		listado = []
		for persona in self.invitados:
			listado.append( u"{} {}".format(persona.correo, persona.nombre))
		return "\n".join(listado)

	@property
	def documentos(self):
		for anexo in self.anexos:
			yield anexo.documento


class AnexosActa(db.Model):
	__tablename__   = 'acta_anexos'
	__table_args__ = { 'schema': 'gestion' }
	__bind_key__ = 'system'

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

	actaid     		= db.Column(db.Integer,  db.ForeignKey('gestion.actas.id'))
	documentohash   = db.Column(UUID(as_uuid=True), db.ForeignKey('doc.archivos.hash'))

	__table_args__  = (db.UniqueConstraint('actaid', 'documentohash', name='nodupesAnexosActa'), { 'schema': 'gestion' })

	acta	        = db.relationship('Acta', back_populates='anexos')
	documento       = db.relationship('Documento')


class MiembrosAsistentes(db.Model):
	__tablename__  = 'acta_asistentes'
	__table_args__ = { 'schema': 'gestion' }
	__bind_key__ = 'system'

	id             = db.Column(db.Integer, primary_key=True)
	personaid      = db.Column(db.BigInteger, db.ForeignKey('usuarios.personas.id'))
	actaid         = db.Column(db.Integer, db.ForeignKey('gestion.actas.id'))

	acta       	   = db.relationship('Acta', back_populates='miembros')
	persona        = db.relationship('Persona')
	__table_args__  = (db.UniqueConstraint('personaid', 'actaid', name='nodupesMiembrosActas'), { 'schema': 'gestion' })


class InvitadosAsistentes(db.Model):
	__tablename__  = 'acta_invitados'
	__table_args__ = { 'schema': 'gestion' }
	__bind_key__ = 'system'

	id             = db.Column(db.Integer, primary_key=True)
	correo         = db.Column(db.String, nullable=False)
	nombre         = db.Column(db.String, nullable=False)
	actaid         = db.Column(db.Integer, db.ForeignKey('gestion.actas.id'))

	acta       	   = db.relationship('Acta', back_populates='invitados')
	__table_args__  = (db.UniqueConstraint('correo', 'actaid', name='nodupesInvitadosActas'), { 'schema': 'gestion' })


class Accion(db.Model):
	__tablename__   = 'actividades'
	__table_args__ = { 'schema': 'gestion' }
	__bind_key__ = 'system'

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

	objetivoid      = db.Column(db.Integer, db.ForeignKey('gestion.objetivos.id'))

	nombre          = db.Column(db.String(200), nullable=False)
	descripcion     = db.Column(db.Text)

	fecha           = db.Column(db.Date)
	estado          = db.Column(db.SmallInteger, default=100)
	dedicacion      = db.Column(db.Integer, default=0)

	objetivo        = db.relationship('Objetivo', back_populates='actividades')
	evidencias      = db.relationship('Evidencia', back_populates='actividad')

	## registros de auditoria
	creado			= db.Column(db.DateTime, default=func.now())
	creadopor		= db.Column(db.Integer, db.ForeignKey('usuarios.personas.id'), nullable=True)
	modificado      = db.Column(db.DateTime, default=func.now(), onupdate=func.now())
	modificadopor	= db.Column(db.Integer, db.ForeignKey('usuarios.personas.id'), nullable=True)


	@property
	def documentos(self):
		for evidencia in self.evidencias:
			yield evidencia.documento

class Evidencia(db.Model):
	__tablename__   = 'evidencias'
	__table_args__ = { 'schema': 'gestion' }
	__bind_key__ = 'system'

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

	actividadid     = db.Column(db.Integer,  db.ForeignKey('gestion.actividades.id'))
	documentohash   = db.Column(UUID(as_uuid=True), db.ForeignKey('doc.archivos.hash'))

	__table_args__  = (db.UniqueConstraint('actividadid', 'documentohash', name='nodupesEvidencia'), { 'schema': 'gestion' })

	actividad       = db.relationship('Accion', back_populates='evidencias')
	documento       = db.relationship('Documento')

class ModuloGestion(db.Model):
	__tablename__   = 'modulo'
	__table_args__ = { 'schema': 'gestion' }
	__bind_key__ = 'system'

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

	basenodeid      = db.Column(db.Integer, db.ForeignKey('gestion.objetivos.id'))
	nombre          = db.Column(db.String(100), nullable=False)
	uri             = db.Column(db.String(100), nullable=False, unique=True)
	etiqueta        = db.Column(db.String(100), nullable=False)

	nodobase       = db.relationship('Objetivo')

	@property
	def icon(self):
	    return self.nodobase.tipo

	@property
	def quorum(self):
	    return AccesosModuloGestion.query.filter(AccesosModuloGestion.moduloid==self.id).count()

	def mvector(self):
	    vector = []
	    for acceso in AccesosModuloGestion.query.filter(AccesosModuloGestion.moduloid==self.id).all():
	        vector.append(acceso.comisionid)

	    return vector

class AccesosModuloGestion(db.Model):
	__tablename__   = 'acceso'
	__table_args__ = { 'schema': 'gestion' }
	__bind_key__ = 'system'

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

	moduloid        = db.Column(db.Integer,  db.ForeignKey('gestion.modulo.id'))
	comisionid      = db.Column(db.Integer,  db.ForeignKey('gestion.comisiones.id'))

	__table_args__  = (db.UniqueConstraint('moduloid', 'comisionid', name='no_dupes_acceso_gestion'), { 'schema': 'gestion' })

	modulo          = db.relationship('ModuloGestion')
	comision        = db.relationship('Comision')


class AccesoGestion():
	def __init__(self):
	    if 'accesogestion' not in g:
	        self.sysadmin = False
	        self.admin = []
	        self.usuario = []
	        for modulo in self.get_modulos():
	            if modulo.nodobase.visible():
	                self.usuario.append(modulo)

	        for comision in Comision.query.join(Miembro).filter(Miembro.personaid==current_user.id, Comision.creado==1).all():
	            if comision.id > 999:
	                self.admin.append(comision.id)
	            elif comision.id == 1:
	                self.sysadmin = True
	                self.admin.append(comision.id)

	        g.accesogestion = {
	                'sysadmin': self.sysadmin,
	                'admin':    self.admin,
	                'usuario':  self.usuario
	                }
	    else:
	        self.sysadmin = g.accesogestion['sysadmin']
	        self.admin    = g.accesogestion['admin']
	        self.usuario  = g.accesogestion['usuario']

	def get_nodes(self):
	    for modulo in self.usuario:
	        yield modulo

	def get_modulos(self):
	    for modulo in ModuloGestion.query.order_by(ModuloGestion.id.asc()).all():
	        yield modulo

	def in_gestion(self):
	    if len(self.usuario) > 0:
	        return True
	    else:
	        return self.sysadmin

	def is_sysadmin(self):
	    return self.sysadmin

	def is_admin(self):
	    if len(self.admin)>0:
	        return True
	    else:
	        return False

	def administrador(self):
	    for item in self.admin:
	        yield Comision.query.get(item)

	def comisiones(self, admin):
	    if admin > 1:
	        yield Comision.query.get(admin)
	        for item in Comision.query.filter(Comision.creado.in_(self.admin), Comision.creado==admin).all():
	            yield item
	    elif self.sysadmin:
	        for item in Comision.query.filter(Comision.creado==1).order_by(Comision.id.asc()).all():
	            yield item

	def valid_users(self, admin):
	    if admin > 1:
	        for item in Miembro.query.join(Comision).filter(Comision.creado==1).distinct(Miembro.personaid).all():
	            yield Persona.query.get(item.personaid)
	    elif self.sysadmin:
	        for item in Persona.query.order_by(Persona.nombres.asc(), Persona.apellidop.asc()).all():
	            yield item
