from extensions import db  
from flask_login import UserMixin
import hashlib
from sqlalchemy.dialects.postgresql import ARRAY
from config import ADMIN_ROLE_ID, GERENTE_ROLE_ID, SUPERVISOR_ROLE_ID, EVALUADO_ROLE_ID, TALENTO_HUMANO_ROLE_ID, DIRECTOR_ROLE_ID

# --- Database Models ---

# Role Model (assuming a 'role' table exists) - Moved this definition BEFORE User model
class Rol(db.Model):
    __tablename__ = 'rol'
    id_rol = db.Column(db.Integer, primary_key=True)
    descripcion = db.Column(db.String(50), unique=True, nullable=False)

    def __repr__(self):
        return f'<Rol {self.descripcion}>'

# Localizacion Model (Level 0 — location/site)
class Localizacion(db.Model):
    __tablename__ = 'localizacion'
    __table_args__ = {'extend_existing': True}
    id_localizacion = db.Column(db.Integer, primary_key=True)
    nombre = db.Column(db.String(200))
    valido = db.Column(db.Boolean, default=True)

    def __repr__(self):
        return f'<Localizacion {self.nombre}>'

# DivisionesGenerales Model (Level 1 — Dirección)
class DivisionesGenerales(db.Model):
    __tablename__ = 'divisiones_generales'
    __table_args__ = {'extend_existing': True}
    id_divisiones_generales = db.Column(db.Integer, primary_key=True)
    nombre = db.Column(db.String(255))
    valido = db.Column(db.Boolean, default=True)
    sede = db.Column(db.Boolean)

    def __repr__(self):
        return f'<DivisionesGenerales {self.nombre}>'

# Unidades Model (Level 2 — Gerencia General)
class Unidades(db.Model):
    __tablename__ = 'unidades'
    __table_args__ = {'extend_existing': True}
    id_unidades = db.Column(db.Integer, primary_key=True)
    nombre = db.Column(db.String(255))
    id_divisiones_generales = db.Column(db.Integer, db.ForeignKey('divisiones_generales.id_divisiones_generales'), nullable=True)
    valido = db.Column(db.Boolean, default=True)

    division = db.relationship('DivisionesGenerales', backref='unidades')

    def __repr__(self):
        return f'<Unidades {self.nombre}>'

# GerenciasGenerales Model (Level 3 — Gerencia de Línea)
class GerenciasGenerales(db.Model):
    __tablename__ = 'gerencias_generales'
    __table_args__ = {'extend_existing': True}
    id_gerencias_generales = db.Column(db.Integer, primary_key=True)
    nombre = db.Column(db.String(255))
    id_unidades = db.Column(db.Integer, db.ForeignKey('unidades.id_unidades'), nullable=True)
    id_divisiones_generales = db.Column(db.Integer, db.ForeignKey('divisiones_generales.id_divisiones_generales'), nullable=True)
    valido = db.Column(db.Boolean, default=True)
    id_estado = db.Column(db.Integer, nullable=True)

    unidad = db.relationship('Unidades', backref='gerencias_generales')
    division = db.relationship('DivisionesGenerales', backref='gerencias_generales')

    def __repr__(self):
        return f'<GerenciasGenerales {self.nombre}>'

# Coordinaciones Model (Level 4 — Coordinación)
class Coordinaciones(db.Model):
    __tablename__ = 'coordinaciones'
    __table_args__ = {'extend_existing': True}
    id_coordinaciones = db.Column(db.Integer, primary_key=True)
    nombre = db.Column(db.String(255))
    id_divisiones_generales = db.Column(db.Integer, db.ForeignKey('divisiones_generales.id_divisiones_generales'), nullable=True)
    id_unidades = db.Column(db.Integer, db.ForeignKey('unidades.id_unidades'), nullable=True)
    id_gerencias_generales = db.Column(db.Integer, db.ForeignKey('gerencias_generales.id_gerencias_generales'), nullable=True)
    valido = db.Column(db.Boolean, default=True)

    gerencia_general = db.relationship('GerenciasGenerales', backref='coordinaciones')
    unidad = db.relationship('Unidades', backref='coordinaciones')
    division = db.relationship('DivisionesGenerales', backref='coordinaciones')

    def __repr__(self):
        return f'<Coordinaciones {self.nombre}>'

# User Model (assuming 'personal' table)
class User(db.Model, UserMixin):
    __tablename__ = 'personal'
    __table_args__ = {'extend_existing': True}

    id_personal = db.Column(db.Integer, primary_key=True)
    cedula = db.Column(db.Integer, nullable=False)
    nombre = db.Column(db.String(100))
    apellido = db.Column(db.String(100))
    nacionalidad = db.Column(db.String(5))
    estatu = db.Column(db.Boolean) # Renamed from 'status' to 'estatu' to match DB
    id_rol = db.Column(db.Integer, db.ForeignKey('rol.id_rol')) # Matches 'id_rol' in DB, corrected from 'id_role'
    password_hash = db.Column(db.String(256))
    usuario = db.Column(db.String(10), unique=True, nullable=False)
    ubicacion = db.relationship('UbicacionPersonal', back_populates='user_details_in_ubicacion', uselist=False, lazy=True)


    # Establish relationship to Role (Role is now defined above)
    rol = db.relationship('Rol', backref='users')

    @property
    def username(self):
        return self.usuario

    @property
    def full_name(self):
        return f"{self.nombre or ''} {self.apellido or ''}".strip()

    @property
    def active(self): # Property to match UserMixin's is_active convention
        return self.estatu

    def set_password(self, password):
        self.password_hash = hashlib.sha256(password.encode('utf-8')).hexdigest()

    def check_password(self, password):
        return self.password_hash == hashlib.sha256(password.encode('utf-8')).hexdigest()

    def get_id(self):
        return str(self.id_personal)

    @property
    def is_default_password(self):
        if not self.usuario or not self.password_hash:
            return False
        return self.password_hash == hashlib.sha256(self.usuario.encode('utf-8')).hexdigest()

    # Role checking properties (NOT methods)
    @property
    def is_admin(self):
        return self.id_rol == ADMIN_ROLE_ID

    @property
    def is_gerente(self):
        return self.id_rol in [GERENTE_ROLE_ID, DIRECTOR_ROLE_ID]

    @property
    def is_director(self):
        return self.id_rol == DIRECTOR_ROLE_ID

    @property
    def is_supervisor(self):
        return self.id_rol == SUPERVISOR_ROLE_ID

    @property
    def is_evaluado(self):
        return self.id_rol == EVALUADO_ROLE_ID

    @property
    def is_talento_humano(self):
        return self.id_rol == TALENTO_HUMANO_ROLE_ID


    def __repr__(self):
        return f'<User {self.usuario}>'





# Año (Year) Model
class Ano(db.Model):
    __tablename__ = 'ano'
    __table_args__ = {'extend_existing': True}
    id_ano = db.Column(db.Integer, primary_key=True)
    descripcion = db.Column(db.String(50), nullable=False, unique=True)

    def __repr__(self):
        return f'<Ano {self.descripcion}>'

# Trimestre (Trimestre) Model
class Trimestre(db.Model):
    __tablename__ = 'trimestre'
    __table_args__ = {'extend_existing': True}
    id_trimestre = db.Column(db.Integer, primary_key=True)
    descripcion = db.Column(db.String(50), nullable=False, unique=True)

    def __repr__(self):
        return f'<Trimestre {self.descripcion}>'

# Rango (Range) Model
class Rango(db.Model):
    __tablename__ = 'rango'
    __table_args__ = {'extend_existing': True}
    id_rango = db.Column(db.Integer, primary_key=True)
    descripcion = db.Column(db.String(50), nullable=False, unique=True)

    def __repr__(self):
        return f'<Rango {self.descripcion}>'

# ODI Model (Objetivos de Desempeño Individual)
class Odi(db.Model):
    __tablename__ = 'odi'
    id_odi = db.Column(db.Integer, primary_key=True)
    descripcion = db.Column(db.String(500))
    peso = db.Column(db.Integer)
    # THE NEW KEY FIELD
    id_personal = db.Column(db.Integer, db.ForeignKey('personal.id_personal'))
    # Relationship to access creator details if needed
    creator = db.relationship('User', backref='my_odis')
        
# OdiPersonal (Assignment) Model
class OdiPersonal(db.Model):
    __tablename__ = 'odi_personal'
    id_odi_personal = db.Column(db.Integer, primary_key=True)
    id_personal = db.Column(db.Integer, db.ForeignKey('personal.id_personal')) # The Evaluated User
    id_odi = db.Column(db.Integer, db.ForeignKey('odi.id_odi')) # The ODI being assigned
    id_ano = db.Column(db.Integer, db.ForeignKey('ano.id_ano'), nullable=False)
    id_trimestre = db.Column(db.Integer, db.ForeignKey('trimestre.id_trimestre'), nullable=False)
    id_rango = db.Column(db.Integer, db.ForeignKey('rango.id_rango'), nullable=False)

    # Relationships to access related data
    personal = db.relationship('User', backref='odi_assignments')
    odi = db.relationship('Odi', backref='personal_assignments')
    ano = db.relationship('Ano', backref='odi_assignments')
    trimestre = db.relationship('Trimestre', backref='odi_assignments')
    rango = db.relationship('Rango', backref='odi_assignments')

    def __repr__(self):
        return f'<OdiPersonal {self.id_personal}-{self.id_odi} ({self.id_ano}/{self.id_trimestre})>'

class UbicacionPersonal(db.Model):
    __tablename__ = 'ubicacion_personal'
    __table_args__ = {'extend_existing': True}

    id_ubicacion_personal = db.Column(db.Integer, primary_key=True)
    id_personal = db.Column(db.Integer, db.ForeignKey('personal.id_personal'), unique=True, nullable=False)

    # New 5-level organizational FK columns
    id_localizacion = db.Column(db.Integer, db.ForeignKey('localizacion.id_localizacion'), nullable=True)
    id_divisiones_generales = db.Column(db.Integer, db.ForeignKey('divisiones_generales.id_divisiones_generales'), nullable=True)
    id_unidades = db.Column(db.Integer, db.ForeignKey('unidades.id_unidades'), nullable=True)
    id_gerencias_generales = db.Column(db.Integer, db.ForeignKey('gerencias_generales.id_gerencias_generales'), nullable=True)
    id_coordinaciones = db.Column(db.Integer, db.ForeignKey('coordinaciones.id_coordinaciones'), nullable=True)

    # Relationship back to User
    user_details_in_ubicacion = db.relationship('User', back_populates='ubicacion', uselist=False, lazy=True)

    # Relationships to org tables
    localizacion = db.relationship('Localizacion', backref='ubicaciones', lazy=True)
    division_general = db.relationship('DivisionesGenerales', backref='ubicaciones', lazy=True)
    unidad = db.relationship('Unidades', backref='ubicaciones', lazy=True)
    gerencia_general = db.relationship('GerenciasGenerales', backref='ubicaciones', lazy=True)
    coordinacion = db.relationship('Coordinaciones', backref='ubicaciones', lazy=True)

    def __repr__(self):
        return f'<UbicacionPersonal Personal:{self.id_personal} Loc:{self.id_localizacion} Div:{self.id_divisiones_generales} Uni:{self.id_unidades} Ger:{self.id_gerencias_generales} Coord:{self.id_coordinaciones}>'


class Competencia(db.Model):
    __tablename__ = 'competencia'
    __table_args__ = {'extend_existing': True}
    id_competencia = db.Column(db.Integer, primary_key=True)
    descripcion = db.Column(db.String(500), nullable=False, unique=True) # Added unique constraint
    peso = db.Column(db.Integer, nullable=False)

    def __repr__(self):
        return f'<Competencia {self.descripcion} (Peso: {self.peso})>'

# CompetenciaPersonal (Assignment) Model
class CompetenciaPersonal(db.Model):
    __tablename__ = 'competencia_personal'
    __table_args__ = (
        db.UniqueConstraint('id_personal', 'id_competencia', 'id_ano', 'id_trimestre', name='uq_competencia_personal_assignment'),
        {'extend_existing': True}
    )
    id_competencia_personal = db.Column(db.Integer, primary_key=True)
    id_competencia = db.Column(db.Integer, db.ForeignKey('competencia.id_competencia'), nullable=False)
    id_personal = db.Column(db.Integer, db.ForeignKey('personal.id_personal'), nullable=False)
    id_rango = db.Column(db.Integer, db.ForeignKey('rango.id_rango'), nullable=False)
    id_ano = db.Column(db.Integer, db.ForeignKey('ano.id_ano'), nullable=False)
    id_trimestre = db.Column(db.Integer, db.ForeignKey('trimestre.id_trimestre'), nullable=False)

    # Relationships to access related data
    competencia = db.relationship('Competencia', backref='personal_assignments')
    personal = db.relationship('User', backref='competencia_assignments')
    rango = db.relationship('Rango', backref='competencia_assignments')
    ano = db.relationship('Ano', backref='competencia_assignments')
    trimestre = db.relationship('Trimestre', backref='competencia_assignments')

    def __repr__(self):
        return f'<CompetenciaPersonal {self.id_personal}-{self.id_competencia} ({self.id_ano}/{self.id_trimestre})>'

# Escala Model
class Escala(db.Model):
    __tablename__ = 'escala'
    id_escala = db.Column(db.Integer, primary_key=True)
    minimo = db.Column(db.Integer, nullable=False)
    maximo = db.Column(db.Integer) # Maximo can be NULL
    descripcion = db.Column(db.String(255), nullable=False)
    requiere_curso = db.Column(db.Boolean)

    def __repr__(self):
        return f'<Escala {self.descripcion} (Min: {self.minimo}, Max: {self.maximo})>'


class Evaluacion(db.Model):
    __tablename__ = 'evaluacion'
    id_evaluacion = db.Column(db.Integer, primary_key=True)
    id_personal = db.Column(db.Integer, db.ForeignKey('personal.id_personal'), nullable=False)
    id_ano = db.Column(db.Integer, db.ForeignKey('ano.id_ano'), nullable=False)
    id_trimestre = db.Column(db.Integer, db.ForeignKey('trimestre.id_trimestre'), nullable=False)
    
    # Using ARRAY for PostgreSQL integer arrays
    # You might need to import ARRAY from sqlalchemy.dialects.postgresql
    # from sqlalchemy.dialects.postgresql import ARRAY
    ids_odi_personal = db.Column(db.ARRAY(db.Integer))
    ids_competencia_personal = db.Column(db.ARRAY(db.Integer))
    
    aprobacion = db.Column(db.Boolean)
    observacion = db.Column(db.Text)
    ids_curso = db.Column(db.Text) # As per your table schema

    # Define relationships if you want to access related objects directly
    personal = db.relationship('User', foreign_keys=[id_personal], backref=db.backref('evaluaciones', lazy=True))
    ano = db.relationship('Ano', backref=db.backref('evaluaciones', lazy=True))
    trimestre = db.relationship('Trimestre', backref=db.backref('evaluaciones', lazy=True))
    
    # NEW: Track who performed the evaluation
    id_evaluador = db.Column(db.Integer, db.ForeignKey('personal.id_personal'))
    evaluador = db.relationship('User', foreign_keys=[id_evaluador], backref='evaluaciones_realizadas')

    observacion_th = db.Column(db.Text)
    
    __table_args__ = (
        db.UniqueConstraint('id_personal', 'id_ano', 'id_trimestre', name='unique_evaluacion_group'),
    )

    def __repr__(self):
        return f'<Evaluacion Personal_ID: {self.id_personal}, Ano: {self.id_ano}, Trimestre: {self.id_trimestre}>'

class CursoPersonal(db.Model):
    __tablename__ = 'curso_personal'
    id_curso = db.Column(db.Integer, primary_key=True, autoincrement=True)
    descripcion = db.Column(db.String(255))
    path_to_file = db.Column(db.Text)
    id_personal = db.Column(db.Integer, db.ForeignKey('personal.id_personal')) # Assuming your User model's table is named 'personal'
    id_ano = db.Column(db.Integer, db.ForeignKey('ano.id_ano'))
    id_trimestre = db.Column(db.Integer, db.ForeignKey('trimestre.id_trimestre'))

    # Optional: Define relationships if you need them for easier querying
    personal = db.relationship('User', backref='ids_curso', lazy=True)
    ano_obj = db.relationship('Ano', backref='ids_curso', lazy=True)
    trimestre_obj = db.relationship('Trimestre', backref='ids_curso', lazy=True)

    def __repr__(self):
        return f"<CursoPersonal {self.descripcion} for Personal {self.id_personal} in {self.id_ano}/{self.id_trimestre}>"