from flask import Blueprint, render_template, redirect, url_for, flash, request, jsonify
from flask_login import login_required, current_user
from app.models import Job
from app import db
import json
import subprocess
import os

jobs_bp = Blueprint('jobs', __name__, url_prefix='/jobs')

@jobs_bp.route('/submit')
@login_required
def submit():
    return render_template('jobs/submit.html')

@jobs_bp.route('/debug/test-step2')
@login_required
def debug_test_step2():
    """Debug endpoint to test step2 template with mock data"""
    if not current_user.is_admin:
        return jsonify({'error': 'Admin access required'}), 403
    
    # Mock data similar to what we expect from scenario scan
    organized_data = {
        "drivers": {
            "diag_protocol_stack": ["diag_protocol_stack_init_test"]
        },
        "application_layer": {
            "data_pool": ["data_pool_init_test"],
            "actuator_manager": ["actuator_manager_init_test2", "actuator_manager_init_test"],
            "event_system": ["event_system_init_test"]
        }
    }
    
    scenario_map = {
        "diag_protocol_stack_init_test": "drivers/diag_protocol_stack/test/diag_protocol_stack_init_test.test_scenario.xml",
        "data_pool_init_test": "application_layer/DP_stack/data_pool/test/data_pool_init_test.test_scenario.xml",
        "actuator_manager_init_test2": "application_layer/business_stack/actuator_manager/test/actuator_manager_init_test2.test_scenario.xml",
        "actuator_manager_init_test": "application_layer/business_stack/actuator_manager/test/actuator_manager_init_test.test_scenario.xml",
        "event_system_init_test": "application_layer/business_stack/event_system/test/event_system_init_test.test_scenario.xml"
    }
    
    try:
        return render_template('jobs/submit_step2.html', 
                             branch_name='test_branch', 
                             organized_data=organized_data,
                             scenario_map=scenario_map)
    except Exception as e:
        return jsonify({
            'error': str(e),
            'type': type(e).__name__,
            'template_exists': True
        })

@jobs_bp.route('/debug/ssh-test')
@login_required
def debug_ssh_test():
    """Debug endpoint to test SSH connectivity"""
    if not current_user.is_admin:
        return jsonify({'error': 'Admin access required'}), 403
    
    try:
        ssh_password = os.environ.get('SSH_PASSWORD', 'default_password')
        ssh_host = os.environ.get('SSH_HOST', 'remote_host')
        ssh_user = os.environ.get('SSH_USER', 'asf')
        ssh_port = os.environ.get('SSH_PORT', '22')
        
        # SSH options for better connectivity
        ssh_options = f"-p {ssh_port} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
        
        # Test basic SSH connectivity
        test_cmd = f"sshpass -p '{ssh_password}' ssh {ssh_options} {ssh_user}@{ssh_host} 'echo SSH_CONNECTION_SUCCESS'"
        result = subprocess.run(test_cmd, shell=True, capture_output=True, text=True, timeout=30)
        
        return jsonify({
            'ssh_config': {
                'user': ssh_user,
                'host': ssh_host,
                'port': ssh_port,
                'password_set': bool(ssh_password and ssh_password != 'default_password')
            },
            'command_executed': test_cmd.replace(ssh_password, '***'),
            'test_result': {
                'returncode': result.returncode,
                'stdout': result.stdout,
                'stderr': result.stderr
            },
            'success': result.returncode == 0 and 'SSH_CONNECTION_SUCCESS' in result.stdout
        })
        
    except Exception as e:
        return jsonify({
            'error': str(e),
            'success': False
        })

@jobs_bp.route('/submit/step1', methods=['POST'])
@login_required
def submit_step1():
    branch_name = request.form.get('branch_name')
    
    if not branch_name:
        return jsonify({
            'success': False,
            'error': 'Branch name is required',
            'output': ''
        })
    
    # Validate branch exists on remote
    try:
        # Get SSH configuration from environment variables
        ssh_password = os.environ.get('SSH_PASSWORD', 'default_password')
        ssh_host = os.environ.get('SSH_HOST', 'remote_host')
        ssh_user = os.environ.get('SSH_USER', 'asf')
        ssh_port = os.environ.get('SSH_PORT', '22')
        
        print(f"[DEBUG] Starting branch validation for: {branch_name}")
        print(f"[DEBUG] SSH Config - User: {ssh_user}, Host: {ssh_host}, Port: {ssh_port}")
        
        # SSH options for better connectivity
        ssh_options = f"-p {ssh_port} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
        
        # First, clone the repository
        clone_cmd = f"sshpass -p '{ssh_password}' ssh {ssh_options} {ssh_user}@{ssh_host} './TPF/gitea_repo_controller.sh clone'"
        print(f"[DEBUG] Executing clone command: {clone_cmd.replace(ssh_password, '***')}")
        
        clone_result = subprocess.run(clone_cmd, shell=True, capture_output=True, text=True, timeout=60)
        
        print(f"[DEBUG] Clone result - Return code: {clone_result.returncode}")
        print(f"[DEBUG] Clone stdout: {clone_result.stdout}")
        print(f"[DEBUG] Clone stderr: {clone_result.stderr}")
        
        # Then, checkout the branch
        checkout_cmd = f"sshpass -p '{ssh_password}' ssh {ssh_options} {ssh_user}@{ssh_host} './TPF/gitea_repo_controller.sh checkout {branch_name}'"
        print(f"[DEBUG] Executing checkout command: {checkout_cmd.replace(ssh_password, '***')}")
        
        checkout_result = subprocess.run(checkout_cmd, shell=True, capture_output=True, text=True, timeout=60)
        
        print(f"[DEBUG] Checkout result - Return code: {checkout_result.returncode}")
        print(f"[DEBUG] Checkout stdout: {checkout_result.stdout}")
        print(f"[DEBUG] Checkout stderr: {checkout_result.stderr}")
        
        # Combine all output for analysis
        full_output = f"CLONE OUTPUT:\n{clone_result.stdout}\n{clone_result.stderr}\n\nCHECKOUT OUTPUT:\n{checkout_result.stdout}\n{checkout_result.stderr}"
        
        # Check if checkout was successful
        # Look for "fatal:" in the output which indicates failure
        checkout_failed = (
            "fatal:" in checkout_result.stdout.lower() or 
            "fatal:" in checkout_result.stderr.lower() or
            checkout_result.returncode != 0
        )
        
        print(f"[DEBUG] Checkout failed: {checkout_failed}")
        
        if checkout_failed:
            error_msg = f'Branch "{branch_name}" not found on remote. Please push the branch first.'
            
            # Try to extract more specific error from output
            if "fatal:" in checkout_result.stdout:
                fatal_line = [line for line in checkout_result.stdout.split('\n') if 'fatal:' in line.lower()]
                if fatal_line:
                    error_msg += f" Error: {fatal_line[0].strip()}"
            elif "fatal:" in checkout_result.stderr:
                fatal_line = [line for line in checkout_result.stderr.split('\n') if 'fatal:' in line.lower()]
                if fatal_line:
                    error_msg += f" Error: {fatal_line[0].strip()}"
            
            return jsonify({
                'success': False,
                'error': error_msg,
                'output': full_output,
                'debug': {
                    'clone_returncode': clone_result.returncode,
                    'checkout_returncode': checkout_result.returncode,
                    'branch_name': branch_name
                }
            })
        
        # If successful, run scenario scan to get available scenarios
        print(f"[DEBUG] Running scenario scan...")
        scan_cmd = f"sshpass -p '{ssh_password}' ssh {ssh_options} {ssh_user}@{ssh_host} 'python3 TPF/Sensor_hub_repo/Tools/TPF/scenario_scan.py'"
        print(f"[DEBUG] Executing scan command: {scan_cmd.replace(ssh_password, '***')}")
        
        scan_result = subprocess.run(scan_cmd, shell=True, capture_output=True, text=True, timeout=120)
        
        print(f"[DEBUG] Scan result - Return code: {scan_result.returncode}")
        print(f"[DEBUG] Scan stdout: {scan_result.stdout}")
        print(f"[DEBUG] Scan stderr: {scan_result.stderr}")
        
        # Parse the JSON response from scenario scan
        try:
            scan_data = json.loads(scan_result.stdout)
            organized_data = scan_data.get('organized_data', {})
            scenario_map = scan_data.get('scenario_map', {})
            
            print(f"[DEBUG] Found {len(scenario_map)} scenarios in {len(organized_data)} categories")
            
        except json.JSONDecodeError as e:
            print(f"[ERROR] Failed to parse scenario scan JSON: {e}")
            print(f"[ERROR] Raw output: {scan_result.stdout}")
            # Fallback to mock data if scan fails
            organized_data = {
                "drivers": {
                    "diag_protocol_stack": ["diag_protocol_stack_init_test"]
                },
                "application_layer": {
                    "data_pool": ["data_pool_init_test"],
                    "actuator_manager": ["actuator_manager_init_test2", "actuator_manager_init_test"],
                    "event_system": ["event_system_init_test"]
                }
            }
            scenario_map = {
                "diag_protocol_stack_init_test": "drivers/diag_protocol_stack/test/diag_protocol_stack_init_test.test_scenario.xml",
                "data_pool_init_test": "application_layer/DP_stack/data_pool/test/data_pool_init_test.test_scenario.xml",
                "actuator_manager_init_test2": "application_layer/business_stack/actuator_manager/test/actuator_manager_init_test2.test_scenario.xml",
                "actuator_manager_init_test": "application_layer/business_stack/actuator_manager/test/actuator_manager_init_test.test_scenario.xml",
                "event_system_init_test": "application_layer/business_stack/event_system/test/event_system_init_test.test_scenario.xml"
            }
        
        print(f"[DEBUG] Branch validation successful for: {branch_name}")
        
        return jsonify({
            'success': True,
            'organized_data': organized_data,
            'scenario_map': scenario_map,
            'message': f'Branch "{branch_name}" validated successfully',
            'output': full_output,
            'debug': {
                'clone_returncode': clone_result.returncode,
                'checkout_returncode': checkout_result.returncode,
                'scan_returncode': scan_result.returncode if 'scan_result' in locals() else 'N/A',
                'branch_name': branch_name,
                'scenarios_found': len(scenario_map)
            }
        })
        
    except subprocess.TimeoutExpired:
        error_msg = 'Branch validation timed out. Please try again.'
        print(f"[ERROR] {error_msg}")
        return jsonify({
            'success': False,
            'error': error_msg,
            'output': 'Command timed out after 60 seconds'
        })
    except Exception as e:
        error_msg = f'Error validating branch: {str(e)}'
        print(f"[ERROR] {error_msg}")
        return jsonify({
            'success': False,
            'error': error_msg,
            'output': f'Exception: {str(e)}'
        })

@jobs_bp.route('/submit/step2', methods=['POST'])
@login_required
def submit_step2():
    branch_name = request.form.get('branch_name')
    scenario_map_json = request.form.get('scenario_map')
    selected_scenarios_json = request.form.get('selected_scenarios')
    
    try:
        scenario_map = json.loads(scenario_map_json) if scenario_map_json else {}
        selected_scenarios = json.loads(selected_scenarios_json) if selected_scenarios_json else []
    except json.JSONDecodeError:
        flash('Invalid scenario data', 'error')
        return redirect(url_for('jobs.submit'))
    
    if not selected_scenarios:
        flash('Please select at least one scenario', 'error')
        return redirect(url_for('jobs.submit'))
    
    return render_template('jobs/submit_step3.html', 
                         branch_name=branch_name, 
                         scenarios=selected_scenarios,
                         scenario_map=scenario_map)

@jobs_bp.route('/submit/step2-validated', methods=['POST'])
@login_required
def submit_step2_validated():
    try:
        branch_name = request.form.get('branch_name')
        organized_data_json = request.form.get('organized_data')
        scenario_map_json = request.form.get('scenario_map')
        
        print(f"[DEBUG] Step2 - Branch: {branch_name}")
        print(f"[DEBUG] Step2 - Organized data length: {len(organized_data_json) if organized_data_json else 0}")
        print(f"[DEBUG] Step2 - Scenario map length: {len(scenario_map_json) if scenario_map_json else 0}")
        
        if not branch_name:
            print("[ERROR] Step2 - No branch name provided")
            flash('Branch name is required', 'error')
            return redirect(url_for('jobs.submit'))
        
        try:
            organized_data = json.loads(organized_data_json) if organized_data_json else {}
            scenario_map = json.loads(scenario_map_json) if scenario_map_json else {}
            
            print(f"[DEBUG] Step2 - Parsed organized_data keys: {list(organized_data.keys())}")
            print(f"[DEBUG] Step2 - Parsed scenario_map count: {len(scenario_map)}")
            
        except json.JSONDecodeError as e:
            print(f"[ERROR] Step2 - JSON decode error: {e}")
            flash('Invalid scenario data', 'error')
            return redirect(url_for('jobs.submit'))
        
        print(f"[DEBUG] Step2 - Rendering template with {len(organized_data)} layers")
        
        return render_template('jobs/submit_step2.html', 
                             branch_name=branch_name, 
                             organized_data=organized_data,
                             scenario_map=scenario_map)
    
    except Exception as e:
        print(f"[ERROR] Step2 - Unexpected error: {str(e)}")
        print(f"[ERROR] Step2 - Error type: {type(e).__name__}")
        import traceback
        print(f"[ERROR] Step2 - Traceback: {traceback.format_exc()}")
        flash(f'Error loading scenario selection: {str(e)}', 'error')
        return redirect(url_for('jobs.submit'))
@login_required
def submit_step2():
    branch_name = request.form.get('branch_name')
    selected_scenarios = request.form.getlist('scenarios')
    
    if not selected_scenarios:
        flash('Please select at least one scenario', 'error')
        return redirect(url_for('jobs.submit'))
    
    return render_template('jobs/submit_step3.html', 
                         branch_name=branch_name, 
                         scenarios=selected_scenarios)

@jobs_bp.route('/submit/step3', methods=['POST'])
@login_required
def submit_step3():
    branch_name = request.form.get('branch_name')
    scenarios_json = request.form.get('scenarios')
    scenario_map_json = request.form.get('scenario_map')
    environment = request.form.get('environment')
    
    try:
        scenarios = json.loads(scenarios_json) if scenarios_json else []
        scenario_map = json.loads(scenario_map_json) if scenario_map_json else {}
    except json.JSONDecodeError:
        flash('Invalid scenario data', 'error')
        return redirect(url_for('jobs.submit'))
    
    return render_template('jobs/submit_step4.html',
                         branch_name=branch_name,
                         scenarios=scenarios,
                         scenario_map=scenario_map,
                         environment=environment)

@jobs_bp.route('/submit/final', methods=['POST'])
@login_required
def submit_final():
    branch_name = request.form.get('branch_name')
    scenarios_json = request.form.get('scenarios')
    scenario_map_json = request.form.get('scenario_map')
    environment = request.form.get('environment')
    test_mode = request.form.get('test_mode')
    keep_devbenches = request.form.get('keep_devbenches') == 'on'
    reuse_results = request.form.get('reuse_results') == 'on'
    
    try:
        scenarios = json.loads(scenarios_json) if scenarios_json else []
        scenario_map = json.loads(scenario_map_json) if scenario_map_json else {}
    except json.JSONDecodeError:
        flash('Invalid scenario data', 'error')
        return redirect(url_for('jobs.submit'))
    
    job = Job(
        user_id=current_user.id,
        branch_name=branch_name,
        scenarios=json.dumps(scenarios),  # Store as JSON string
        environment=environment,
        test_mode=test_mode,
        keep_devbenches=keep_devbenches,
        reuse_results=reuse_results,
        status='in_progress'
    )
    
    db.session.add(job)
    db.session.commit()
    
    # TODO: Start test execution in background using scenario_map
    
    flash('Test job submitted successfully', 'success')
    return redirect(url_for('dashboard.index'))

@jobs_bp.route('/<int:job_id>')
@login_required
def view_job(job_id):
    job = Job.query.get_or_404(job_id)
    
    if not current_user.is_admin and job.user_id != current_user.id:
        flash('Access denied', 'error')
        return redirect(url_for('dashboard.index'))
    
    return jsonify({
        'id': job.id,
        'submitter': job.submitter.username,
        'branch_name': job.branch_name,
        'scenarios': job.scenarios,
        'environment': job.environment,
        'test_mode': job.test_mode,
        'status': job.status,
        'submitted_at': job.submitted_at.strftime('%Y-%m-%d %H:%M:%S'),
        'completed_at': job.completed_at.strftime('%Y-%m-%d %H:%M:%S') if job.completed_at else None,
        'duration': job.duration,
        'keep_devbenches': job.keep_devbenches,
        'reuse_results': job.reuse_results,
        'results_path': job.results_path
    })

@jobs_bp.route('/<int:job_id>/abort', methods=['POST'])
@login_required
def abort_job(job_id):
    job = Job.query.get_or_404(job_id)
    
    if not current_user.is_admin and job.user_id != current_user.id:
        return jsonify({'error': 'Access denied'}), 403
    
    if job.status == 'in_progress':
        job.status = 'aborted'
        db.session.commit()
        # TODO: Kill the running process
        return jsonify({'success': True})
    
    return jsonify({'error': 'Job is not in progress'}), 400
