from datetime import datetime, timedelta
from user_agents import parse
from app.extensions import db


class UserSession(db.Model):
    __tablename__ = "user_sessions"

    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
    session_id = db.Column(db.String(255), nullable=False, unique=True)
    ip_address = db.Column(db.String(45), nullable=False)
    user_agent = db.Column(db.Text, nullable=True)
    device_type = db.Column(db.String(50), nullable=True)
    browser = db.Column(db.String(100), nullable=True)
    os = db.Column(db.String(100), nullable=True)
    country = db.Column(db.String(100), nullable=True)
    city = db.Column(db.String(100), nullable=True)
    login_time = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
    logout_time = db.Column(db.DateTime, nullable=True)
    last_activity = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
    is_active = db.Column(db.Boolean, default=True, nullable=False)
    session_duration = db.Column(db.Integer, default=0)

    user = db.relationship("User", backref=db.backref("sessions", lazy=True))

    def __init__(self, user_id, session_id, ip_address, user_agent=None):
        self.user_id = user_id
        self.session_id = session_id
        self.ip_address = ip_address
        self.user_agent = user_agent

        if user_agent:
            ua = parse(user_agent)
            self.device_type = self._get_device_type(ua)
            self.browser = f"{ua.browser.family} {ua.browser.version_string}"
            self.os = f"{ua.os.family} {ua.os.version_string}"

    def _get_device_type(self, ua):
        if ua.is_mobile:
            return "mobile"
        if ua.is_tablet:
            return "tablet"
        if ua.is_pc:
            return "desktop"
        return "unknown"

    def update_activity(self):
        self.last_activity = datetime.utcnow()
        if self.login_time:
            duration = datetime.utcnow() - self.login_time
            self.session_duration = int(duration.total_seconds() / 60)
        db.session.commit()

    def end_session(self):
        self.logout_time = datetime.utcnow()
        self.is_active = False
        if self.login_time:
            duration = self.logout_time - self.login_time
            self.session_duration = int(duration.total_seconds() / 60)
        db.session.commit()

    @staticmethod
    def get_active_sessions():
        return UserSession.query.filter_by(is_active=True).all()

    @staticmethod
    def get_sessions_by_period(period="today"):
        now = datetime.utcnow()

        if period == "today":
            start_date = now.replace(hour=0, minute=0, second=0, microsecond=0)
        elif period == "yesterday":
            start_date = (now - timedelta(days=1)).replace(hour=0, minute=0, second=0, microsecond=0)
            end_date = now.replace(hour=0, minute=0, second=0, microsecond=0)
            return UserSession.query.filter(
                UserSession.login_time >= start_date,
                UserSession.login_time < end_date,
            ).all()
        elif period == "this_week":
            start_date = now - timedelta(days=now.weekday())
            start_date = start_date.replace(hour=0, minute=0, second=0, microsecond=0)
        elif period == "last_week":
            start_date = now - timedelta(days=now.weekday() + 7)
            start_date = start_date.replace(hour=0, minute=0, second=0, microsecond=0)
            end_date = now - timedelta(days=now.weekday())
            end_date = end_date.replace(hour=0, minute=0, second=0, microsecond=0)
            return UserSession.query.filter(
                UserSession.login_time >= start_date,
                UserSession.login_time < end_date,
            ).all()
        elif period == "this_month":
            start_date = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
        elif period == "last_month":
            if now.month == 1:
                start_date = now.replace(year=now.year - 1, month=12, day=1, hour=0, minute=0, second=0, microsecond=0)
                end_date = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
            else:
                start_date = now.replace(month=now.month - 1, day=1, hour=0, minute=0, second=0, microsecond=0)
                end_date = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
            return UserSession.query.filter(
                UserSession.login_time >= start_date,
                UserSession.login_time < end_date,
            ).all()
        else:
            start_date = now.replace(hour=0, minute=0, second=0, microsecond=0)

        return UserSession.query.filter(UserSession.login_time >= start_date).all()


class ActivityLog(db.Model):
    __tablename__ = "activity_logs"

    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
    session_id = db.Column(db.String(255), db.ForeignKey("user_sessions.session_id"), nullable=False)
    action = db.Column(db.String(100), nullable=False)
    endpoint = db.Column(db.String(255), nullable=True)
    method = db.Column(db.String(10), nullable=True)
    timestamp = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
    response_time = db.Column(db.Float, nullable=True)

    user = db.relationship("User", backref=db.backref("activity_logs", lazy=True))
    session = db.relationship("UserSession", backref=db.backref("activity_logs", lazy=True))
