#!/usr/bin/env python3
"""Minimal Bottle web app for clipboard and evaluation operations."""

import ast
import subprocess
from bottle import Bottle, request, response, template, run, TEMPLATE_PATH
import os
import logging
import threading

from services.exam_service import ExamService
from services.ssh_service import SSHService
from services.evaluation_service import EvaluationService

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)

logger = logging.getLogger(__name__)

app = Bottle()

# Constants
EXAM_ASSET_PATH = "/var/opt/assets/"

# In-memory storage
clipboard_history = []
evaluation_results = []
evaluation_status = {
    'running': False,
    'completed': False,
    'error': None
}

# Initialize services
exam_service = ExamService(EXAM_ASSET_PATH)
ssh_service = SSHService()
evaluation_service = EvaluationService(exam_service, ssh_service)


@app.route('/ping', method='GET')
def ping():
    """Health check endpoint."""
    response.content_type = 'application/json'
    return {'pong': 'ok'}


@app.route('/clipboard', method='POST')
def clipboard():
    """Store clipboard content and execute xclip command."""
    try:
        data = request.json
        if not data or 'content' not in data:
            response.status = 400
            return {'error': 'Missing content field'}
        
        clipboard_content = data['content']
        # Replace single quotes with escaped version
        clipboard_content = clipboard_content.replace("'", "'\\''")
        
        # Execute xclip command
        command = f"echo -n '{clipboard_content}' | xclip -selection clipboard &"
        subprocess.Popen(command, shell=True)
        
        response.content_type = 'application/json'
        return {'status': 'ok'}
    except Exception as e:
        response.status = 500
        return {'error': str(e)}


def _run_evaluation():
    """Background task to run exam evaluation."""
    global evaluation_results, evaluation_status
    
    try:
        evaluation_status['running'] = True
        evaluation_status['completed'] = False
        evaluation_status['error'] = None
        
        logger.info("Starting evaluation...")
        
        # Clear previous results
        evaluation_results = []
        
        # Run evaluation
        results = evaluation_service.evaluate_exam()
        
        # Store results
        evaluation_results = results
        
        evaluation_status['running'] = False
        evaluation_status['completed'] = True
        
        logger.info(f"Evaluation completed. {len(results)} questions evaluated.")
        
    except Exception as e:
        logger.error(f"Evaluation failed: {e}")
        evaluation_status['running'] = False
        evaluation_status['completed'] = True
        evaluation_status['error'] = str(e)


@app.route('/evaluate', method='POST')
def evaluate():
    """Trigger evaluation asynchronously and return immediately."""
    global evaluation_status
    
    # Check if evaluation is already running
    if evaluation_status['running']:
        response.status = 409
        return {'error': 'Evaluation already in progress'}
    
    # Start evaluation in background thread
    thread = threading.Thread(target=_run_evaluation, daemon=True)
    thread.start()
    
    response.status = 202
    response.content_type = 'application/json'
    return {
        'status': 'accepted',
        'message': 'Evaluation started in background'
    }


@app.route('/assessment-result', method='GET')
def assessment_result():
    """Get evaluation results as JSON (API format)."""
    response.content_type = 'application/json'
    
    if not evaluation_results:
        response.status = 404
        return {'error': 'No evaluation results available'}
    
    # Transform results to API format (minimal data)
    api_results = []
    for result in evaluation_results:
        # Transform steps to exclude description, output, error
        api_steps = []
        for step in result['steps']:
            api_step = {
                'order': step['order'],
                'points_possible': step['points_possible'],
                'points_awarded': step['points_awarded'],
                'success': step['success'],
                'attempts': step['attempts']
            }
            api_steps.append(api_step)
        
        api_result = {
            'question_id': result['question_id'],
            'question_order': result['question_order'],
            'steps': api_steps,
            'total_points_awarded': result['total_points_awarded'],
            'total_possible_points': result['total_possible_points']
        }
        api_results.append(api_result)
    
    return {
        'status': 'ok',
        'results': api_results
    }

@app.route('/answer', method='GET')
def answer():
    """Render HTML showing exam answers and explanations."""
    # Check if exam is in progress
    if len(evaluation_results) == 0:
        return template('answer', exam_in_progress=True, error=None, exam_summary={}, questions=[])
    
    # Load exam data
    exam_data = exam_service.load_exam_data()
    
    if not exam_data:
        response.status = 404
        return template('answer', exam_in_progress=False, error="Exam data not found", exam_summary={}, questions=[])
    
    # Extract exam summary and questions
    exam_summary = exam_service.get_exam_summary(exam_data)
    questions = exam_service.get_questions_with_answers(exam_data)
    
    return template('answer', exam_in_progress=False, error=None, exam_summary=exam_summary, questions=questions)


@app.route('/result', method='GET')
def result():
    """Render HTML showing evaluation results with scores."""
    # Check if evaluation results exist
    if not evaluation_results:
        return template('result', 
                       error="Your assessment results are not yet available. Please ensure you have completed and submitted your work.",
                       exam_summary={},
                       results=[])
    
    # Load exam data for summary
    exam_data = exam_service.load_exam_data()
    exam_summary = {}
    if exam_data and exam_data.get('success'):
        exam_summary = exam_service.get_exam_summary(exam_data)
    
    # Calculate total scores
    total_points_awarded = sum(r['total_points_awarded'] for r in evaluation_results)
    total_possible_points = sum(r['total_possible_points'] for r in evaluation_results)
    percentage = round((total_points_awarded / total_possible_points * 100), 2) if total_possible_points > 0 else 0
    
    return template('result',
                   error=None,
                   exam_summary=exam_summary,
                   results=evaluation_results,
                   total_points_awarded=total_points_awarded,
                   total_possible_points=total_possible_points,
                   percentage=percentage)


def main():
    """Entry point for console script."""
    import sys
    import site
    
    # Set template lookup path to views directory
    # Try multiple locations to handle both development and installed scenarios
    app_dir = os.path.dirname(os.path.abspath(__file__))
    
    # Try these locations in order:
    possible_paths = [
        os.path.join(app_dir, 'views'),  # Development: same dir as app.py
        os.path.join(sys.prefix, 'views'),  # Normal install: {prefix}/views
    ]
    
    # For user installs (--user), check user base directory
    try:
        user_base = site.USER_BASE
        if user_base:
            possible_paths.append(os.path.join(user_base, 'views'))  # User install: ~/.local/views
    except:
        pass
    
    # Add more fallback locations
    possible_paths.extend([
        os.path.join(os.path.dirname(app_dir), 'views'),  # Parent of site-packages
        '/usr/share/sailor-remote-agent/views',  # System install location
        '/usr/local/share/sailor-remote-agent/views',  # Local system install
    ])
    
    # Also check in site-packages directories
    try:
        for site_dir in site.getsitepackages():
            possible_paths.append(os.path.join(site_dir, 'views'))
    except:
        pass
    
    # Find the first existing views directory
    views_path = None
    for path in possible_paths:
        if os.path.exists(path) and os.path.isdir(path):
            views_path = path
            logger.info(f"Found views directory at: {views_path}")
            break
    
    if not views_path:
        views_path = os.path.join(app_dir, 'views')  # Fallback
        logger.warning(f"Views directory not found in any expected location. Using: {views_path}")
        logger.warning(f"Checked paths: {possible_paths}")
    
    # Set both the app template lookup and global TEMPLATE_PATH
    app.template_lookup = [views_path]
    # Clear and set the global TEMPLATE_PATH for bottle's template() function
    TEMPLATE_PATH.clear()
    TEMPLATE_PATH.append(views_path)
    
    print("--------------------------------")
    print("Running version 0.2.7")
    print(f"asset path is: {EXAM_ASSET_PATH}")
    print(f"template lookup: {views_path}")
    print("--------------------------------")
    # Use port 8081 if 8080 is unavailable, or allow override via environment variable
    run(app, host='localhost', port=9000, debug=True)


if __name__ == '__main__':
    main()
