# app.py (Moodle Integration Flask App)
from flask import Flask, request, render_template, jsonify
import requests
import json
import os
import logging
from flask_cors import CORS
from dotenv import load_dotenv

load_dotenv()  # This loads variables from .env into os.environ


# Configure logging to show debug messages
logging.basicConfig(level=logging.DEBUG)

app = Flask(__name__)

# Apply CORS after app is defined
CORS(app) # This allows all origins by default

MOODLE_URL = os.environ.get('MOODLE_URL')
MOODLE_TOKEN = os.environ.get('MOODLE_TOKEN')

# Check if environment variables are loaded
if MOODLE_URL:
    app.logger.info(f"MOODLE_URL loaded: {MOODLE_URL}")
else:
    app.logger.error("MOODLE_URL not found in environment variables!")

if MOODLE_TOKEN:
    app.logger.info(f"MOODLE_TOKEN loaded: {MOODLE_TOKEN[:5]}...")
else:
    app.logger.error("MOODLE_TOKEN not found in environment variables!")


# --- Configuration ---
# IMPORTANT: Replace with your actual Moodle API details.
# You can get your service token from Moodle's Site administration -> Server -> Web services -> Manage tokens
# Moodle config
MOODLE_LMS_URL = "https://lms.collnetwork.net/webservice/rest/server.php"
MOODLE_LMS_TOKEN = "33e292b8342c48d69351d9cad2e4408c"


# Termii API configuration
TERMI_SMS_API_KEY = "TLkSeSYNznSfvQqqPIxjjUWyFNkyVsQSJVbflmcjaxxSKaQODFCQwynkoVPZJG"
TERMI_SMS_API_URL = "https://v3.api.termii.com/api/sms/send"
TERMI_SENDER_ID = "Collnetwork" # This is the "from" field in the Termii payload


# Function to call Moodle Web Services
def call_moodle_ws(function_name, **kwargs):
    # Log the full Moodle URL and function name before the request
    app.logger.info(f"Attempting to call Moodle WS: {function_name} at URL: {MOODLE_URL}")
    
    params = {
        'wstoken': MOODLE_TOKEN,
        'wsfunction': function_name,
        'moodlewsrestformat': 'json', # Ensure JSON response
    }
    
    payload = {}
    for key, value in kwargs.items():
        if isinstance(value, list) and all(isinstance(item, dict) for item in value):
            for i, item_dict in enumerate(value):
                for sub_key, sub_value in item_dict.items():
                    payload[f'{key}[{i}][{sub_key}]'] = sub_value
        elif isinstance(value, list):
            for i, item_value in enumerate(value):
                payload[f'{key}[{i}]'] = item_value
        else:
            payload[key] = value

    app.logger.debug(f"Calling Moodle WS: {function_name} with payload: {payload}")

    try:
        # Pass the payload as 'data' for x-www-form-urlencoded
        response = requests.post(MOODLE_URL, params=params, data=payload, timeout=30)
        
        # Log the raw response and status code before attempting to parse it
        app.logger.debug(f"Moodle WS '{function_name}' response status code: {response.status_code}")
        app.logger.debug(f"Moodle WS '{function_name}' raw response text: '{response.text}'")

        response.raise_for_status() # Raises an HTTPError for bad responses (4xx or 5xx)
        
        json_response = None
        try:
            json_response = response.json()
            app.logger.debug(f"Moodle WS '{function_name}' parsed JSON: {json_response}")
        except json.JSONDecodeError as jde:
            app.logger.error(f"JSONDecodeError for Moodle WS '{function_name}': {jde}. Raw response: '{response.text}'")
            if function_name == 'enrol_manual_enrol_users' and response.text.strip() == '':
                app.logger.info(f"Moodle WS '{function_name}' returned empty string, assuming success.")
                return []
            
            return {'error': f"Invalid JSON response from Moodle for {function_name}", 'raw_response': response.text}
        
        if json_response is None:
            if function_name == 'enrol_manual_enrol_users':
                app.logger.info(f"Moodle WS '{function_name}' returned None from response.json(), assuming success for enrolment.")
                return []
            else:
                app.logger.error(f"Moodle WS '{function_name}' returned None from response.json(). Raw response: '{response.text}'")
                return {'error': f"Empty or unexpected response from Moodle for {function_name}", 'raw_response': response.text}

        if isinstance(json_response, dict) and 'exception' in json_response:
            app.logger.error(f"Moodle WS '{function_name}' returned an error: {json_response.get('message', 'No message')} (Debug: {json_response.get('debuginfo', 'N/A')})")
            return {'error': json_response['message'], 'debuginfo': json_response.get('debuginfo')}
        
        return json_response
    
    except requests.exceptions.RequestException as e:
        app.logger.error(f"Network or HTTP error calling Moodle WS '{function_name}': {e}")
        error_message = str(e)
        moodle_response_text = None

        if hasattr(e, 'response') and e.response is not None:
            moodle_response_text = e.response.text
            app.logger.error(f"Moodle response content (raw): {moodle_response_text}")
            try:
                moodle_error_details = e.response.json()
                if 'exception' in moodle_error_details:
                    return {'error': moodle_error_details['message'], 'debuginfo': moodle_error_details.get('debuginfo')}
            except json.JSONDecodeError:
                pass

        return {'error': f"Failed to connect to Moodle: {error_message}", 'moodle_response': moodle_response_text}

# app.py (Moodle Integration Flask App) - New SMS endpoint

# Route to serve the HTML file
@app.route('/')
def index():
    # Pass the request.host_url to the template to build absolute URLs
    return render_template('sms.html')

# New proxy route to get Moodle courses
@app.route('/moodle/courses')
def get_moodle_courses():
    params = {
        'wstoken': MOODLE_LMS_TOKEN,
        'wsfunction': 'core_course_get_courses',
        'moodlewsrestformat': 'json'
    }
    try:
        response = requests.get(MOODLE_LMS_URL, params=params)
        response.raise_for_status()
        return jsonify(response.json())
    except requests.exceptions.RequestException as e:
        app.logger.error(f"Error fetching Moodle courses: {e}")
        return jsonify({'error': 'Failed to fetch courses'}), 500

# New proxy route to get Moodle participants for a specific course
@app.route('/moodle/participants')
def get_moodle_participants():
    course_id = request.args.get('courseid')
    if not course_id:
        return jsonify({'error': 'Missing courseid parameter'}), 400

    params = {
        'wstoken': MOODLE_LMS_TOKEN,
        'wsfunction': 'core_enrol_get_enrolled_users',
        'moodlewsrestformat': 'json',
        'courseid': course_id
    }
    try:
        response = requests.get(MOODLE_LMS_URL, params=params)
        response.raise_for_status()
        return jsonify(response.json())
    except requests.exceptions.RequestException as e:
        app.logger.error(f"Error fetching Moodle participants: {e}")
        return jsonify({'error': 'Failed to fetch participants'}), 500

# The provided route to send SMS
# This function is a placeholder and should be updated based on your specific
# phone number formatting needs for the Termii API.
def format_phone_number(phone_number):
    """
    Formats a phone number to a format accepted by the Termii API.
    Example: '09012345678' -> '2349012345678'
    """
    # Remove all non-digit characters
    digits_only = ''.join(filter(str.isdigit, phone_number))
    
    # Example logic: if it starts with '0', replace with '234'
    if digits_only.startswith('0'):
        return '234' + digits_only[1:]
    
    return digits_only


@app.route('/sms/send', methods=['POST'])
def send_sms_via_termii():
    recipients_json = request.form.get('recipients')
    message = request.form.get('message')

    if not recipients_json or not message:
        return jsonify({'status': 'error', 'message': 'Missing recipient or message data'}), 200

    try:
        recipients = json.loads(recipients_json)
        total_recipients = len(recipients)
        app.logger.info(f"Received SMS request for {total_recipients} recipients.")
        app.logger.debug(f"Recipient list: {recipients}")

        success_count = 0
        failed_numbers = []

        for recipient in recipients:
            formatted_recipient = format_phone_number(recipient)
            termii_payload = {
                "to": formatted_recipient,
                "from": TERMI_SENDER_ID,
                "sms": message,
                "type": "plain",
                "channel": "generic",
                "api_key": TERMI_SMS_API_KEY
            }
            termii_headers = {
                'Content-Type': 'application/json',
            }

            try:
                termii_response = requests.post(
                    TERMI_SMS_API_URL,
                    headers=termii_headers,
                    json=termii_payload,
                    timeout=30
                )
                termii_response.raise_for_status()
                # Check for success status from Termii's response if possible
                # (The exact success response format would depend on Termii's API)
                success_count += 1
            except requests.exceptions.RequestException as e:
                app.logger.error(f"Error sending to {formatted_recipient}: {e}")
                if hasattr(e, 'response') and e.response is not None:
                    app.logger.error(f"Termii API raw response: {e.response.text}")
                failed_numbers.append(formatted_recipient)

        message_status = f'SMS sent to {success_count}/{total_recipients} recipients.'
        if failed_numbers:
            message_status += f' Failed for: {", ".join(failed_numbers)}'

        return jsonify({
            'status': 'success',
            'message': message_status,
            'failed': failed_numbers
        }), 200

    except json.JSONDecodeError as jde:
        app.logger.error(f"Failed to decode recipients JSON: {jde}")
        return jsonify({'status': 'error', 'message': f'Invalid JSON for recipients: {jde}'}), 200

    except Exception as e:
        app.logger.error(f"Unexpected error: {e}")
        return jsonify({'status': 'error', 'message': f'Unexpected error: {e}'}), 200

@app.route('/enrol', methods=['POST'])
def enrol_lecturer():
    data = request.get_json()
    if not data:
        app.logger.error("Received an invalid JSON data payload.")
        return jsonify({'status': 'error', 'message': 'Invalid JSON data'}), 400

    # Log the incoming data from the client
    app.logger.info(f"Received enrolment request with data: {data}")

    lecturer_email = data.get('email')
    lecturer_firstname = data.get('firstName')
    lecturer_lastname = data.get('lastName')
    lecturer_middlename = data.get('middleName', '')
    lecturer_phone = data.get('phone') 
    lecturer_department = data.get('department')
    course_shortnames = data.get('courseShortnames')

    if not lecturer_email or not course_shortnames:
        app.logger.warning("Missing email or course shortnames in request.")
        return jsonify({'status': 'error', 'message': 'Missing email or course shortnames'}), 400

    try:
        user_id = None
        user_exists = False
        new_user_created = False
        message_prefix = "" 
        new_username = ""
        new_password = ""

        # 1. Find Moodle user by email
        app.logger.info(f"Step 1: Looking for user with email '{lecturer_email}'...")
        users_response = call_moodle_ws('core_user_get_users_by_field', field='email', values=[lecturer_email])

        if 'error' in users_response:
            app.logger.error(f"Error checking user existence: {users_response['error']}")
            return jsonify({'status': 'error', 'message': f"Error checking user existence on Moodle: {users_response.get('error', 'Unknown Moodle error')}"}), 500

        if users_response and isinstance(users_response, list) and len(users_response) > 0:
            user_id = users_response[0]['id']
            user_exists = True
            app.logger.info(f"User '{lecturer_email}' found with ID: {user_id}")
        else:
            app.logger.info(f"User '{lecturer_email}' not found, attempting to create.")

        # 2. Create or Update User
        if not user_exists:
            app.logger.info("Step 2: Creating new user...")
            new_username = lecturer_email 
            new_password = "Password123!" 
            
            user_details_for_creation = {
                'username': new_username,
                'password': new_password, 
                'firstname': lecturer_firstname,
                'lastname': lecturer_lastname,
                'middlename': lecturer_middlename,
                'email': lecturer_email,
                'auth': 'manual',
                'createpassword': 0, 
                'phone2': lecturer_phone,
                'department': lecturer_department,
                'city':'OTUOKE',
                'country':'NG',
                'institution': 'Federal University Otuoke Bayelsa State',
            }
            # Log username and password before sending
            app.logger.info(f"Creating user with username: {new_username} and password: {new_password}")

            create_user_response = call_moodle_ws(
                'core_user_create_users',
                users=[user_details_for_creation] 
            )

            if 'error' in create_user_response:
                app.logger.error(f"Error creating user: {create_user_response['error']}")
                return jsonify({'status': 'error', 'message': f'Error creating user on Moodle: {create_user_response.get("error", "Unknown error")}'}), 500
            elif not isinstance(create_user_response, list) or len(create_user_response) == 0:
                app.logger.error(f"Unexpected response from core_user_create_users: {create_user_response}")
                return jsonify({'status': 'error', 'message': 'Failed to create user on Moodle: Unexpected response (user not created).'}), 500
            
            user_id = create_user_response[0]['id']
            app.logger.info(f"User '{lecturer_email}' created with ID: {user_id}")
            new_user_created = True
            message_prefix = "Lecturer created and "
        else:
            app.logger.info("Step 2: User exists, updating details...")
            user_details_for_update = {
                'id': user_id, 
                'email': lecturer_email,
                'middlename': lecturer_middlename,
                'city': 'OTUOKE',
                'country': 'NG'
            }
            if lecturer_firstname: user_details_for_update['firstname'] = lecturer_firstname
            if lecturer_lastname: user_details_for_update['lastname'] = lecturer_lastname
            if lecturer_middlename: user_details_for_update['middlename'] = lecturer_middlename
            if lecturer_phone: user_details_for_update['phone2'] = lecturer_phone
            if lecturer_department: user_details_for_update['department'] = lecturer_department

            update_user_response = call_moodle_ws(
                'core_user_update_users',
                users=[user_details_for_update]
            )

            if 'error' in update_user_response:
                app.logger.error(f"Error updating user {user_id}: {update_user_response['error']}")
                return jsonify({'status': 'error', 'message': f"Error updating user details on Moodle: {update_user_response['error']}"}), 500
            
            app.logger.info(f"User '{lecturer_email}' (ID: {user_id}) updated.")
            message_prefix = "Lecturer details updated and "
            

        # 3. Get Course IDs and prepare enrolments
        app.logger.info("Step 3: Preparing course enrolments...")
        enrolments = []
        role_id = 3 # Default Moodle role ID for "editing teacher". Verify this.
        
        all_courses_response = call_moodle_ws('core_course_get_courses')
        
        if 'error' in all_courses_response:
            app.logger.error(f"Error fetching courses: {all_courses_response['error']}")
            return jsonify({'status': 'error', 'message': f"Error fetching course information from Moodle: {all_courses_response['error']}"}), 500

        moodle_courses = {}
        if isinstance(all_courses_response, list):
            moodle_courses = {course['shortname']: course['id'] for course in all_courses_response}
        else:
            app.logger.error(f"Unexpected response format for core_course_get_courses: {all_courses_response}")
            return jsonify({'status': 'error', 'message': 'Unexpected response fetching course information.'}), 500

        for shortname in course_shortnames:
            course_id = moodle_courses.get(shortname)
            if course_id:
                enrolments.append({
                    'userid': user_id,
                    'courseid': course_id,
                    'roleid': role_id
                })
            else:
                app.logger.warning(f"Course with shortname '{shortname}' not found on Moodle. Skipping enrolment for this course.")
        
        if not enrolments:
            app.logger.warning("No valid courses found for enrolment.")
            return jsonify({'status': 'warning', 'message': f'{message_prefix} no valid courses found for enrolment. User exists: {user_exists}'}), 200

        # 4. Enrol user in courses
        app.logger.info("Step 4: Enrolling user in courses...")
        enrol_response = call_moodle_ws('enrol_manual_enrol_users', enrolments=enrolments)

        if isinstance(enrol_response, dict) and 'error' in enrol_response:
            app.logger.error(f"Error during enrolment: {enrol_response['error']}")
            return jsonify({'status': 'error', 'message': f"Error enrolling user in courses: {enrol_response['error']}"}), 500
        elif isinstance(enrol_response, list):
            app.logger.info(f"Enrolment successful for {len(enrolments)} courses. Moodle response: {enrol_response}")
            # This is a successful enrolment, continue to build the final response message
            pass
        else:
            app.logger.error(f"Unexpected response type from enrol_manual_enrol_users: {type(enrol_response).__name__} - {enrol_response}")
            # This case is a bit ambiguous, but let's assume it was a success.
            # We'll build the final message and return success.
            pass

        # Build the final success message
        final_message = f"{message_prefix}enrolled successfully in Moodle."

        # Conditionally add username/password to the response
        if new_user_created:
            final_message += f"<br>Your Username: <strong>{new_username}</strong><br>Your Temporary Password: <strong>{new_password}</strong>"
        
        final_message += f"<br>Login here: <a href='https://lms.fuotuoke.edu.ng/login/index.php' target='_blank'>LMS Login</a>"

        return jsonify({'status': 'success', 'message': final_message, 'new_user_created': new_user_created, 'username': new_username, 'password': new_password}), 200

    except Exception as e:
        app.logger.exception("An unexpected error occurred during enrolment process.")
        return jsonify({'status': 'error', 'message': f'An internal server error occurred: {e}'}), 500