from flask_sqlalchemy import SQLAlchemy
from datetime import datetime, timedelta
from werkzeug.security import generate_password_hash, check_password_hash
import json

db = SQLAlchemy()

class User(db.Model):
    __tablename__ = 'users'

    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(120), unique=True, nullable=False, index=True)
    password_hash = db.Column(db.String(256), nullable=False)
    full_name = db.Column(db.String(100), nullable=False)
    phone = db.Column(db.String(20), nullable=False)
    blood_group = db.Column(db.String(5), nullable=False, index=True)
    city = db.Column(db.String(50), nullable=False, index=True)
    location = db.Column(db.String(200), nullable=False)
    age = db.Column(db.Integer, nullable=False)
    weight = db.Column(db.Float, nullable=False)
    gender = db.Column(db.String(10), nullable=False)
    is_available = db.Column(db.Boolean, default=True)
    last_donation_date = db.Column(db.Date, nullable=True)
    total_donations = db.Column(db.Integer, default=0)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

    donations = db.relationship('Donation', backref='donor', lazy=True, cascade='all, delete-orphan')
    event_subscriptions = db.relationship('EventSubscription', backref='subscriber', lazy=True, cascade='all, delete-orphan')

    def set_password(self, password):
        self.password_hash = generate_password_hash(password)

    def check_password(self, password):
        return check_password_hash(self.password_hash, password)

    @property
    def is_eligible(self):
        """Check if donor is eligible (56 days recovery period for whole blood)"""
        if not self.last_donation_date:
            return True
        recovery_period = timedelta(days=56)
        return datetime.now().date() >= (self.last_donation_date + recovery_period)

    @property
    def days_until_eligible(self):
        """Days remaining until donor becomes eligible again"""
        if not self.last_donation_date:
            return 0
        recovery_period = timedelta(days=56)
        eligible_date = self.last_donation_date + recovery_period
        days_remaining = (eligible_date - datetime.now().date()).days
        return max(0, days_remaining)

    def to_dict(self, include_private=False):
        data = {
            'id': self.id,
            'full_name': self.full_name,
            'blood_group': self.blood_group,
            'city': self.city,
            'location': self.location,
            'age': self.age,
            'gender': self.gender,
            'total_donations': self.total_donations,
            'is_eligible': self.is_eligible,
            'days_until_eligible': self.days_until_eligible if not self.is_eligible else 0,
            'last_donation_date': self.last_donation_date.isoformat() if self.last_donation_date else None,
            'created_at': self.created_at.isoformat()
        }
        if include_private:
            data.update({
                'email': self.email,
                'phone': self.phone,
                'weight': self.weight,
                'is_available': self.is_available
            })
        return data

class Donation(db.Model):
    __tablename__ = 'donations'

    id = db.Column(db.Integer, primary_key=True)
    donor_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False, index=True)
    donation_date = db.Column(db.Date, nullable=False, default=datetime.now().date)
    units = db.Column(db.Float, default=1.0)
    hospital_name = db.Column(db.String(200), nullable=False)
    hospital_city = db.Column(db.String(50), nullable=False)
    certificate_id = db.Column(db.String(50), unique=True, nullable=False)
    notes = db.Column(db.Text, nullable=True)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)

    def to_dict(self):
        return {
            'id': self.id,
            'donor_id': self.donor_id,
            'donation_date': self.donation_date.isoformat(),
            'units': self.units,
            'hospital_name': self.hospital_name,
            'hospital_city': self.hospital_city,
            'certificate_id': self.certificate_id,
            'notes': self.notes,
            'created_at': self.created_at.isoformat()
        }

class Event(db.Model):
    __tablename__ = 'events'

    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(200), nullable=False)
    description = db.Column(db.Text, nullable=False)
    city = db.Column(db.String(50), nullable=False, index=True)
    venue = db.Column(db.String(200), nullable=False)
    event_date = db.Column(db.DateTime, nullable=False)
    organizer_name = db.Column(db.String(100), nullable=False)
    organizer_contact = db.Column(db.String(50), nullable=False)
    created_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)

    def to_dict(self):
        return {
            'id': self.id,
            'title': self.title,
            'description': self.description,
            'city': self.city,
            'venue': self.venue,
            'event_date': self.event_date.isoformat(),
            'organizer_name': self.organizer_name,
            'organizer_contact': self.organizer_contact,
            'created_at': self.created_at.isoformat()
        }

class EventSubscription(db.Model):
    __tablename__ = 'event_subscriptions'

    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
    city = db.Column(db.String(50), nullable=False)
    subscribed_at = db.Column(db.DateTime, default=datetime.utcnow)

    __table_args__ = (db.UniqueConstraint('user_id', 'city', name='unique_user_city_subscription'),)
