from flask import Flask, render_template, request, redirect, url_for, flash, jsonify, session
from flask_bcrypt import Bcrypt
from flask_login import LoginManager, login_user, logout_user, login_required, current_user
from config import Config
from models import db, User, Major, Seat, Client, AuditLog
from sqlalchemy.exc import SQLAlchemyError
from datetime import datetime

app = Flask(__name__)
app.config.from_object(Config)

db.init_app(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

def log_action(action, details):
    log = AuditLog(user_id=current_user.id if current_user.is_authenticated else None, action=action, details=details)
    db.session.add(log)
    db.session.commit()

@app.route('/', methods=['GET', 'POST'])
def index():
    majors = Major.query.filter_by(is_active=True).all()
    if request.method == 'POST':
        name = request.form.get('name')
        national_id = request.form.get('national_id')
        mobile = request.form.get('mobile')
        major_id = request.form.get('major_id')
        service = request.form.get('service')

        # تولید شماره نوبت جدید
        last_client = Client.query.order_by(Client.ticket_number.desc()).first()
        ticket_number = 1 if not last_client else last_client.ticket_number + 1
        
        status = 'WAITING_UPLOAD' if service in ['UPLOAD', 'BOTH'] else 'WAITING_VERIFICATION'
        price = app.config['PRICE_BOTH'] if service == 'BOTH' else (app.config['PRICE_UPLOAD'] if service == 'UPLOAD' else app.config['PRICE_VERIFICATION'])

        new_client = Client(
            ticket_number=ticket_number, name=name, national_id=national_id, 
            mobile=mobile, major_id=major_id, service_request=service, 
            status=status, price=price
        )
        db.session.add(new_client)
        db.session.commit()
        log_action('CREATE_CLIENT', f'Ticket: {ticket_number}')
        return redirect(url_for('success', ticket=ticket_number, token=new_client.telegram_token))

    return render_template('index.html', majors=majors)

@app.route('/success/<int:ticket>')
def success(ticket):
    token = request.args.get('token')
    return render_template('success.html', ticket=ticket, token=token)

@app.route('/tv')
def tv():
    return render_template('tv.html')

@app.route('/api/tv_data')
def tv_data():
    serving = Client.query.filter(Client.status.in_(['IN_UPLOAD', 'IN_VERIFICATION'])).all()
    waiting = Client.query.filter(Client.status.in_(['WAITING_UPLOAD', 'WAITING_VERIFICATION'])).order_by(Client.created_at).limit(10).all()
    
    return jsonify({
        'serving': [{'ticket': c.ticket_number, 'seat': c.served_by_seat, 'service': 'بارگذاری' if c.status == 'IN_UPLOAD' else 'تأییدیه'} for c in serving],
        'waiting': [{'ticket': c.ticket_number} for c in waiting]
    })

@app.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('admin_dashboard') if current_user.role == 'SUPER_ADMIN' else url_for('operator_dashboard'))
        
    if request.method == 'POST':
        user = User.query.filter_by(username=request.form.get('username')).first()
        if user and bcrypt.check_password_hash(user.password_hash, request.form.get('password')):
            if not user.is_active:
                flash('حساب کاربری شما غیرفعال است.', 'danger')
                return redirect(url_for('login'))
            login_user(user)
            log_action('LOGIN', 'User logged in')
            if user.role == 'SUPER_ADMIN': return redirect(url_for('admin_dashboard'))
            return redirect(url_for('operator_dashboard'))
        flash('نام کاربری یا رمز عبور اشتباه است.', 'danger')
    return render_template('login.html')

@app.route('/logout')
@login_required
def logout():
    log_action('LOGOUT', 'User logged out')
    logout_user()
    return redirect(url_for('login'))

@app.route('/operator')
@login_required
def operator_dashboard():
    seat = Seat.query.filter_by(operator_id=current_user.id).first()
    if not seat:
        return "صندلی برای شما تعریف نشده است. با ادمین تماس بگیرید."
    
    current_client = Client.query.filter_by(served_by_seat=seat.code).filter(Client.status.in_(['IN_UPLOAD', 'IN_VERIFICATION'])).first()
    return render_template('operator.html', seat=seat, current_client=current_client)

@app.route('/operator/call_next', methods=['POST'])
@login_required
def call_next():
    seat = Seat.query.filter_by(operator_id=current_user.id).first()
    if not seat: return jsonify({'status': 'error', 'message': 'No seat assigned'})

    target_status = 'WAITING_UPLOAD' if seat.service_type == 'UPLOAD' else 'WAITING_VERIFICATION'
    new_status = 'IN_UPLOAD' if seat.service_type == 'UPLOAD' else 'IN_VERIFICATION'

    try:
        # ATOMIC OPERATION: استفاده از with_for_update برای جلوگیری از Race Condition
        next_client = Client.query.filter_by(status=target_status).order_by(Client.created_at).with_for_update(skip_locked=True).first()
        
        if next_client:
            next_client.status = new_status
            next_client.served_by_seat = seat.code
            db.session.commit()
            log_action('CALL_NEXT', f'Seat {seat.code} called Ticket {next_client.ticket_number}')
            return redirect(url_for('operator_dashboard'))
        else:
            flash('فردی در صف انتظار نیست.', 'warning')
            db.session.rollback()
    except SQLAlchemyError:
        db.session.rollback()
        flash('خطا در فراخوانی نوبت. دوباره تلاش کنید.', 'danger')

    return redirect(url_for('operator_dashboard'))

@app.route('/operator/finish/<int:client_id>', methods=['POST'])
@login_required
def finish_service(client_id):
    client = Client.query.get_or_404(client_id)
    action = request.form.get('action')

    if action == 'NO_SHOW':
        client.status = 'NO_SHOW'
    else:
        if client.service_request == 'BOTH' and client.status == 'IN_UPLOAD':
            client.status = 'WAITING_VERIFICATION'
        else:
            client.status = 'WAITING_PAYMENT'
    
    client.served_by_seat = None
    db.session.commit()
    log_action(action, f'Ticket {client.ticket_number} finished at {current_user.seat[0].code}')
    return redirect(url_for('operator_dashboard'))

@app.route('/admin')
@login_required
def admin_dashboard():
    if current_user.role != 'SUPER_ADMIN': return "دسترسی غیرمجاز"
    stats = {
        'total': Client.query.count(),
        'waiting': Client.query.filter(Client.status.like('WAITING%')).count(),
        'completed': Client.query.filter_by(status='PAID').count()
    }
    recent_logs = AuditLog.query.order_by(AuditLog.created_at.desc()).limit(10).all()
    return render_template('admin.html', stats=stats, logs=recent_logs)

# دستور خط فرمان برای ساخت اولیه دیتابیس
@app.cli.command("init-db")
def init_db():
    db.create_all()
    if not User.query.filter_by(username='admin').first():
        admin = User(username='admin', password_hash=bcrypt.generate_password_hash('admin123').decode('utf-8'), display_name='مدیر کل', role='SUPER_ADMIN')
        db.session.add(admin)
        db.session.commit()
        print("Database initialized. Admin user created (admin / admin123).")
        
@app.route('/setup')
def setup():
    db.create_all()
    if not User.query.filter_by(username='admin').first():
        admin = User(username='admin', password_hash=bcrypt.generate_password_hash('admin123').decode('utf-8'), display_name='مدیر کل', role='SUPER_ADMIN')
        db.session.add(admin)
        db.session.commit()
    return "Database Setup Complete!"
if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)