from flask import Flask, request, jsonify, render_template, redirect, url_for, flash, session
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from authlib.integrations.flask_client import OAuth
import requests
import json
import os
from dotenv import load_dotenv
from openai import OpenAI
from datetime import datetime, timedelta

# Load environment variables FIRST
load_dotenv()

app = Flask(__name__)
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'your-secret-key-here')
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URL', 'sqlite:///tutor.db')

# Initialize extensions
db = SQLAlchemy(app)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'

# Yoco configuration
app.config['YOCO_SECRET_KEY'] = os.getenv('YOCO_SECRET_KEY')
app.config['YOCO_PUBLIC_KEY'] = os.getenv('YOCO_PUBLIC_KEY')

# Debug: Check if Google OAuth credentials are loaded
google_client_id = os.getenv('GOOGLE_CLIENT_ID')
google_client_secret = os.getenv('GOOGLE_CLIENT_SECRET')

print(f"Google Client ID loaded: {bool(google_client_id)}")
print(f"Google Client Secret loaded: {bool(google_client_secret)}")
print(f"Yoco Secret Key loaded: {bool(app.config['YOCO_SECRET_KEY'])}")

# OAuth configuration
oauth = OAuth(app)
if google_client_id and google_client_secret and 'your-google-client-id' not in google_client_id:
    google = oauth.register(
        name='google',
        client_id=google_client_id,
        client_secret=google_client_secret,
        access_token_url='https://oauth2.googleapis.com/token',
        authorize_url='https://accounts.google.com/o/oauth2/auth',
        api_base_url='https://www.googleapis.com/oauth2/v1/',
        userinfo_endpoint='https://openidconnect.googleapis.com/v1/userinfo',
        client_kwargs={'scope': 'openid email profile'},
        jwks_uri='https://www.googleapis.com/oauth2/v3/certs'
    )
else:
    print("❌ Google OAuth credentials missing or still using placeholders - OAuth will not work!")

# Initialize OpenAI
client = OpenAI(api_key=os.getenv('OPENAI_API_KEY'))

# Database Models
class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(120), unique=True, nullable=False)
    name = db.Column(db.String(100), nullable=False)
    provider = db.Column(db.String(20), nullable=False)
    is_premium = db.Column(db.Boolean, default=False)
    subscription_id = db.Column(db.String(100), nullable=True)
    questions_asked = db.Column(db.Integer, default=0)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)

class Payment(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    yoco_charge_id = db.Column(db.String(100), nullable=True)
    amount = db.Column(db.Integer, nullable=False)  # Amount in cents
    currency = db.Column(db.String(3), default='ZAR')
    status = db.Column(db.String(20), default='pending')
    created_at = db.Column(db.DateTime, default=datetime.utcnow)

class QuestionLog(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    question = db.Column(db.Text, nullable=False)
    subject = db.Column(db.String(50), nullable=False)
    grade = db.Column(db.String(10), nullable=False)
    language = db.Column(db.String(10), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

# Language and subject configurations
LANGUAGES = {
    'en': 'English',
    'zu': 'isiZulu',
    'xh': 'isiXhosa',
    'af': 'Afrikaans'
}

SUBJECT_TRANSLATIONS = {
    'Mathematics': {'en': 'Mathematics', 'zu': 'Izibalo', 'xh': 'Imathematika', 'af': 'Wiskunde'},
    'Physical Sciences': {'en': 'Physical Sciences', 'zu': 'Izibalo Zemvelo', 'xh': 'Izibalo Zomzimba', 'af': 'Fisiese Wetenskappe'},
    'Life Sciences': {'en': 'Life Sciences', 'zu': 'Izibalo Zokuphila', 'xh': 'Izibalo Zokuphila', 'af': 'Lewenswetenskappe'},
    'Technology': {'en': 'Technology', 'zu': 'Ukuthuthukiswa', 'xh': 'Ulwandiso', 'af': 'Tegnologie'},
    'General': {'en': 'General', 'zu': 'Okujikelezile', 'xh': 'Okubanzi', 'af': 'Algemeen'}
}

SA_CONTEXT = """
You are a South African educational tutor specializing in CAPS curriculum (Grades 7-12). 
Always:
1. Reference South African context (e.g., local examples, currency in ZAR, metric system)
2. Align with CAPS learning outcomes
3. Respond in the requested language: {language}
4. For math responses:
   - Use LaTeX formatting for ALL mathematical expressions
   - Wrap inline math in \( ... \)
   - Wrap display math (equations, formulas) in \[ ... \]
   - Show step-by-step solutions with clear explanations
5. When using Afrikaans, Zulu, or Xhosa:
   - Use appropriate technical terms where they exist
   - For complex STEM terms without direct translation, use English term with explanation in local language
   - Maintain proper grammar and orthography
6. For STEM subjects:
   - Mathematics: Focus on problem-solving with local applications (e.g., load-shedding calculations)
   - Physical Sciences: Use SA examples (e.g., mining in Rustenburg, renewable energy in Northern Cape)
   - Life Sciences: Reference local biodiversity (e.g., fynbos, Kruger National Park)
   - Technology: Include SA innovations (e.g., solar cookers, water purification)
"""

# Yoco Payment Functions
def create_yoco_charge(token, amount, currency='ZAR'):
    """Create a charge using Yoco API"""
    url = "https://payments.yoco.com/api/charges"
    
    headers = {
        'Content-Type': 'application/json',
        'Authorization': f'Bearer {app.config["YOCO_SECRET_KEY"]}'
    }
    
    data = {
        'token': token,
        'amountInCents': amount,
        'currency': currency
    }
    
    try:
        response = requests.post(url, headers=headers, json=data)
        return response.json(), response.status_code
    except Exception as e:
        return {'error': str(e)}, 500

# Routes
@app.route('/')
def index():
    """Home page - shows different content based on authentication"""
    if current_user.is_authenticated:
        return redirect(url_for('dashboard'))
    return render_template('index.html', 
                         languages=LANGUAGES, 
                         subjects=SUBJECT_TRANSLATIONS,
                         user=current_user.is_authenticated)

@app.route('/dashboard')
@login_required
def dashboard():
    """Main question-asking dashboard for logged-in users"""
    return render_template('dashboard.html', 
                         languages=LANGUAGES, 
                         subjects=SUBJECT_TRANSLATIONS,
                         user=current_user,
                         questions_asked=current_user.questions_asked,
                         is_premium=current_user.is_premium)

@app.route('/login')
def login():
    return render_template('login.html')

@app.route('/login/google')
def google_login():
    if not google_client_id or 'your-google-client-id' in google_client_id:
        flash('Google OAuth is not properly configured. Please contact administrator.', 'error')
        return redirect(url_for('login'))
    
    try:
        redirect_uri = url_for('google_auth', _external=True)
        return oauth.google.authorize_redirect(redirect_uri)
    except Exception as e:
        flash(f'OAuth error: {str(e)}', 'error')
        return redirect(url_for('login'))

@app.route('/login/google/callback')
def google_auth():
    try:
        token = oauth.google.authorize_access_token()
        
        if not token:
            flash('Authorization failed. Please try again.', 'error')
            return redirect(url_for('login'))
        
        user_info = oauth.google.get('userinfo').json()
        
        if user_info and 'email' in user_info:
            user = User.query.filter_by(email=user_info['email']).first()
            
            if not user:
                user = User(
                    email=user_info['email'],
                    name=user_info.get('name', user_info['email']),
                    provider='google'
                )
                db.session.add(user)
                db.session.commit()
                flash('Account created successfully!', 'success')
            else:
                flash('Logged in successfully!', 'success')
            
            login_user(user)
            return redirect(url_for('dashboard'))
        else:
            flash('Could not retrieve user information from Google.', 'error')
            return redirect(url_for('login'))
            
    except Exception as e:
        flash(f'Authentication failed: {str(e)}', 'error')
        return redirect(url_for('login'))

@app.route('/logout')
@login_required
def logout():
    logout_user()
    flash('You have been logged out successfully.', 'info')
    return redirect(url_for('index'))

@app.route('/pricing')
def pricing():
    return render_template('pricing.html', 
                         yoco_public_key=app.config['YOCO_PUBLIC_KEY'],
                         user=current_user.is_authenticated)

@app.route('/subscribe')
@login_required
def subscribe():
    """Payment page where users complete their subscription"""
    if current_user.is_premium:
        flash('You are already a premium member!', 'info')
        return redirect(url_for('dashboard'))
    
    return render_template('subscribe.html',
                         yoco_public_key=app.config['YOCO_PUBLIC_KEY'],
                         user=current_user)

@app.route('/process-payment', methods=['POST'])
@login_required
def process_payment():
    """Process Yoco payment"""
    try:
        data = request.get_json()
        token = data.get('token')
        
        if not token:
            return jsonify({'success': False, 'error': 'No payment token provided'}), 400
        
        # Process payment with Yoco (R99.00 = 9900 cents)
        amount = 9900  # R99.00 in cents
        result, status_code = create_yoco_charge(token, amount)
        
        if status_code == 201 and result.get('status') == 'successful':
            # Payment successful
            current_user.is_premium = True
            current_user.questions_asked = 0  # Reset counter
            
            # Record payment
            payment = Payment(
                user_id=current_user.id,
                yoco_charge_id=result.get('id'),
                amount=amount,
                status='completed'
            )
            db.session.add(payment)
            db.session.commit()
            
            return jsonify({
                'success': True,
                'message': 'Payment successful! You now have premium access.'
            })
        else:
            # Payment failed
            error_msg = result.get('error', 'Payment failed. Please try again.')
            return jsonify({
                'success': False,
                'error': error_msg
            }), 400
            
    except Exception as e:
        return jsonify({
            'success': False,
            'error': f'Payment processing error: {str(e)}'
        }), 500

@app.route('/payment-success')
@login_required
def payment_success():
    flash('Payment successful! You now have premium access.', 'success')
    return redirect(url_for('dashboard'))

@app.route('/payment-cancel')
def payment_cancel():
    flash('Payment was cancelled.', 'info')
    return redirect(url_for('pricing'))

@app.route('/ask', methods=['POST'])
@login_required
def ask_tutor():
    try:
        if not current_user.is_premium and current_user.questions_asked >= 3:
            return jsonify({
                'error': 'Free tier limit reached. You can ask 3 questions per day. Upgrade to premium for unlimited questions!',
                'limit_reached': True
            }), 429
        
        data = request.get_json()
        user_question = data.get('question', '').strip()
        subject = data.get('subject', 'Mathematics')
        grade = data.get('grade', '10')
        language = data.get('language', 'en')
        
        if not user_question:
            return jsonify({'error': 'Question cannot be empty'}), 400
            
        if language not in LANGUAGES:
            language = 'en'
            
        lang_name = LANGUAGES[language]
        
        prompt = f"""
        {SA_CONTEXT.format(language=lang_name)}
        
        Subject: {subject}
        Grade Level: {grade}
        Curriculum: South African CAPS
        Language: {lang_name}
        
        Student Question: "{user_question}"
        
        Provide a clear, step-by-step explanation using South African context. 
        For math problems:
        - Use LaTeX formatting for ALL mathematical expressions
        - Wrap inline math in \( ... \)
        - Wrap display math (equations, formulas) in \[ ... \]
        - Show all calculation steps clearly
        For science, include real SA examples.
        Keep explanations at appropriate grade level.
        """
        
        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {"role": 'system', "content": SA_CONTEXT.format(language=lang_name)},
                {"role": 'user', "content": prompt}
            ],
            temperature=0.7,
            max_tokens=800
        )
        
        answer = response.choices[0].message.content.strip()
        
        question_log = QuestionLog(
            user_id=current_user.id,
            question=user_question,
            subject=subject,
            grade=grade,
            language=language
        )
        current_user.questions_asked += 1
        db.session.add(question_log)
        db.session.commit()
        
        return jsonify({'answer': answer})
        
    except Exception as e:
        return jsonify({'error': f'An error occurred: {str(e)}'}), 500

# Initialize database
with app.app_context():
    db.create_all()

if __name__ == '__main__':
    app.run(debug=True, port=5000)