from datetime import datetime, timezone
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash

from .extensions import db

ROLE_ADMIN = "admin"
ROLE_OPERATOR = "operator"
ROLE_VIEWER = "viewer"
ROLES = (ROLE_ADMIN, ROLE_OPERATOR, ROLE_VIEWER)


def utcnow():
    return datetime.now(timezone.utc)


class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=True)
    password_hash = db.Column(db.String(255), nullable=False)
    role = db.Column(db.String(20), nullable=False, default=ROLE_VIEWER)
    is_active_user = db.Column(db.Boolean, default=True, nullable=False)
    created_at = db.Column(db.DateTime, default=utcnow)

    def set_password(self, password: str) -> None:
        self.password_hash = generate_password_hash(password)

    def check_password(self, password: str) -> bool:
        return check_password_hash(self.password_hash, password)

    @property
    def is_active(self):
        # overrides UserMixin.is_active so disabled accounts can't log in
        return self.is_active_user

    def __repr__(self):
        return f"<User {self.username} ({self.role})>"


class Device(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    hostname = db.Column(db.String(255), nullable=False)
    port = db.Column(db.Integer, nullable=False, default=22)
    username = db.Column(db.String(100), nullable=False)
    auth_type = db.Column(db.String(10), nullable=False, default="password")  # 'password' | 'sshkey'
    secret_encrypted = db.Column(db.LargeBinary, nullable=False)
    key_passphrase_encrypted = db.Column(db.LargeBinary, nullable=True)
    site = db.Column(db.String(100), nullable=True)
    notes = db.Column(db.Text, nullable=True)
    is_active = db.Column(db.Boolean, default=True, nullable=False)
    created_at = db.Column(db.DateTime, default=utcnow)
    created_by_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=True)

    created_by = db.relationship("User")

    def __repr__(self):
        return f"<Device {self.name} {self.hostname}>"


class ConfigChangeLog(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    device_id = db.Column(db.Integer, db.ForeignKey("device.id"), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
    timestamp = db.Column(db.DateTime, default=utcnow)
    action = db.Column(db.String(20), nullable=False)  # commit | rollback | commit_check_failed
    diff_text = db.Column(db.Text, nullable=True)
    comment = db.Column(db.Text, nullable=True)
    result = db.Column(db.String(20), nullable=False)  # success | failure
    error_message = db.Column(db.Text, nullable=True)
    rollback_id = db.Column(db.Integer, nullable=True)
    confirm_minutes = db.Column(db.Integer, nullable=True)
    pending_confirmation = db.Column(db.Boolean, default=False, nullable=False)
    confirmed_at = db.Column(db.DateTime, nullable=True)

    device = db.relationship("Device")
    user = db.relationship("User")
