import os
import secrets
from functools import wraps
from flask import (Flask, render_template, request, redirect, url_for, flash,
                   session, abort)
from config import Config
from extensions import db
from models import (Application, REQUIRED_FIELDS, GENDERS, EDUCATION_LEVELS,
                    EMPLOYMENT_STATUSES, LANGUAGES, LEARNING_DURATIONS, TRACKS,
                    CHALLENGES, REASONS, HEARD_FROM)
from analytics import build_analytics

# Program details surfaced in the template. Edit these placeholders to real values.
PROGRAM = {
    'name': 'Predev',
    'parent': 'CodNesta Group SARL',
    'cohort': '[Cohort — Month Year]',
    'duration': '[12 weeks]',
    'format': '[In-person, Nkongsamba / Online / Hybrid]',
    'fee': '[Free / Scholarship / XAF ____]',
    'start_date': '[DD Month YYYY]',
    'seats': '[30]',
    'contact_email': 'info@codnesta.com',
    'location': 'Nkongsamba, Cameroon',
}

FORM_OPTIONS = {
    'genders': GENDERS, 'education': EDUCATION_LEVELS, 'employment': EMPLOYMENT_STATUSES,
    'languages': LANGUAGES, 'learning_durations': LEARNING_DURATIONS, 'tracks': TRACKS,
    'challenges': CHALLENGES, 'reasons': REASONS, 'heard_from': HEARD_FROM,
}


def _csrf_token():
    """Lightweight per-session CSRF token (Flask-WTF is incompatible with Flask 3.1+)."""
    if '_csrf_token' not in session:
        session['_csrf_token'] = secrets.token_hex(16)
    return session['_csrf_token']


def _check_csrf(form):
    return session.get('_csrf_token') and form.get('csrf_token') == session.get('_csrf_token')


def login_required(view):
    @wraps(view)
    def wrapped(*args, **kwargs):
        if not session.get('is_admin'):
            return redirect(url_for('admin_login', next=request.path))
        return view(*args, **kwargs)
    return wrapped


def create_app():
    app = Flask(__name__)
    app.config.from_object(Config)
    db.init_app(app)

    with app.app_context():
        db.create_all()

    app.jinja_env.globals['csrf_token'] = _csrf_token

    # ---------------- Public landing + application ----------------
    @app.route('/')
    def index():
        return render_template('index.html', program=PROGRAM, options=FORM_OPTIONS)

    @app.route('/apply', methods=['POST'])
    def apply():
        f = request.form
        if not _check_csrf(f):
            flash('Your session expired. Please try submitting again.', 'error')
            return redirect(url_for('index', _anchor='apply'))

        required = ['fullname', 'email', 'phone', 'city', 'motivation']
        if any(not f.get(x, '').strip() for x in required) or not f.get('consent'):
            flash('Please fill in all required fields and accept the consent.', 'error')
            return redirect(url_for('index', _anchor='apply'))

        def as_int(name):
            v = (f.get(name) or '').strip()
            return int(v) if v.isdigit() else None

        app_row = Application(
            full_name=f.get('fullname', '').strip(),
            email=f.get('email', '').strip(),
            phone=f.get('phone', '').strip(),
            gender=f.get('gender', ''),
            age=as_int('age'),
            country=f.get('country', '').strip(),
            city=f.get('city', '').strip(),
            education=f.get('education', ''),
            employment_status=f.get('employment_status', ''),
            has_programming_experience=(f.get('has_programming_experience') == 'Yes'),
            programming_languages=', '.join(f.getlist('programming_languages')),
            learning_duration=f.get('learning_duration', ''),
            has_projects=(f.get('has_projects') == 'Yes'),
            internship_experience=(f.get('internship_experience') == 'Yes'),
            team_project_experience=(f.get('team_project_experience') == 'Yes'),
            challenges=', '.join(f.getlist('challenges')),
            reason_for_joining=f.get('reason_for_joining', ''),
            weekly_hours=as_int('weekly_hours'),
            commitment_score=as_int('commitment_score'),
            motivation=f.get('motivation', '').strip(),
            track=f.get('track', ''),
            heard_from=f.get('heard_from', ''),
            portfolio=f.get('portfolio', '').strip(),
        )
        app_row.status = 'complete' if app_row.is_complete else 'incomplete'
        db.session.add(app_row)
        db.session.commit()
        flash('🎉 Application received! We\'ll review it and get back to you soon.', 'success')
        return redirect(url_for('index', _anchor='apply'))

    # ---------------- Admin auth ----------------
    @app.route('/admin/login', methods=['GET', 'POST'])
    def admin_login():
        if session.get('is_admin'):
            return redirect(url_for('admin_dashboard'))
        if request.method == 'POST':
            if not _check_csrf(request.form):
                flash('Session expired, please try again.', 'error')
                return redirect(url_for('admin_login'))
            u = request.form.get('username', '')
            p = request.form.get('password', '')
            if u == app.config['ADMIN_USERNAME'] and p == app.config['ADMIN_PASSWORD']:
                session['is_admin'] = True
                nxt = request.args.get('next') or url_for('admin_dashboard')
                return redirect(nxt)
            flash('Invalid username or password.', 'error')
        return render_template('admin/login.html')

    @app.route('/admin/logout')
    def admin_logout():
        session.pop('is_admin', None)
        flash('You have been logged out.', 'success')
        return redirect(url_for('admin_login'))

    # ---------------- Admin dashboard (Tier 1) ----------------
    @app.route('/admin')
    @app.route('/admin/dashboard')
    @login_required
    def admin_dashboard():
        apps = Application.query.order_by(Application.created_at.desc()).all()
        data = build_analytics(apps)
        return render_template('admin/dashboard.html', data=data, applications=apps,
                               program=PROGRAM)

    return app


app = create_app()

if __name__ == '__main__':
    app.run(host='127.0.0.1', port=5001, debug=True)
