import os
import openai
import logging
import sys
import uuid
import traceback

# Force reconfig logging before other modules use it
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    stream=sys.stdout,  # Ensure it's sent to systemd journal
    force=True          # ✅ Overwrite any earlier configs
)

# Force reconfiguration of logging before any other module uses it
for handler in logging.root.handlers[:]:
    logging.root.removeHandler(handler)
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

from flask import Flask, request, jsonify, session, send_from_directory, render_template, url_for
from flask_cors import CORS
from openai import OpenAI
from prompt_manager import call_openai_prompt
from app_config import get_max_phase
from flask import request
from qa_system import (
    get_next_part,
    get_recommendation,
    get_answer,
    detect_app_id_from_port,
    get_prompt_messages_by_template_name  # ✅ Add this line
)

import MySQLdb
import re

# === OpenAI client setup ===
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

# === App setup ===
app = Flask(__name__, static_folder='static', template_folder='templates')
CORS(app)
app.secret_key = 'super_secret_key'

# === Application-level constants ===
APP_ID = 5001  # could later be dynamic from port
#MAX_PHASE = get_max_phase(APP_ID)
#logging.info(f"MAX PHASE setting from DB: {MAX_PHASE}")

try:
    MAX_PHASE = get_max_phase(APP_ID)
    print(">>>> Reached top-level MAX_PHASE fetch")  # <-- Debug test line
    logging.info(f"MAX PHASE setting from DB: {MAX_PHASE}")
except Exception as e:
    logging.error(f"Initialization error for MAX_PHASE: {e}")

def extract_sound_files(sound_tags):
    """
    Extracts filenames from <sound:filename> tags.
    Example: "<sound:calm_1.mp4><sound:pause.mp4>" → ['calm_1.mp4', 'pause.mp4']
    """
    if not sound_tags:
        return []
    return re.findall(r"<sound:([^>]+)>", sound_tags)

#Get the port from the URL
@app.before_request
def set_app_id_from_port():
    try:
        host = request.host  # e.g. "localhost:5001"
        port = int(host.split(":")[1])
        session['app_id'] = port  # Save to session or global if needed
        logging.info(f"Detected APP_ID from port: {port}")
    except Exception as e:
        logging.error(f"Could not extract port from host: {e}")

# === Utility ===
def parse_instructions(phase_text):
    segments = re.split(r'(<sound:[\w-]+>)', phase_text)
    sanitized_segments = []
    sound_files = set()

    for segment in segments:
        if "<sound:" in segment:
            sound_marker = re.search(r'<sound:([\w-]+)>', segment)
            if sound_marker:
                filename = sound_marker.group(1)
                sanitized_segments.append({"type": "sound", "value": filename})
                sound_files.add(filename)
        else:
            text_content = segment.strip()
            if text_content:
                sanitized_segments.append({"type": "text", "value": text_content})

    return sanitized_segments, list(sound_files)

# === Routes ===

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

@app.route('/static/<path:path>')
def static_files(path):
    return send_from_directory('static', path)

@app.route("/api/prompt/<int:prompt_id>", methods=["POST"])
def run_prompt(prompt_id):
    data = request.get_json()
    user_input = data.get("user_input", "")
    output = call_openai_prompt(prompt_id, user_input)
    return jsonify({"output": output})

@app.route('/reset-phase', methods=['POST'])
def reset_phase():
    session.clear()
    session['phase'] = 0
    return jsonify({"message": "Phase reset to 0"}), 200


def segment_instructions_XXXXXX(text, sound_tags):
    segments = []

    # Handle instruction text line-by-line
    if text:
        for line in text.splitlines():
            clean = line.strip()
            if clean:
                segments.append({"type": "text", "value": clean})

    # Then add sounds (in order)
    if sound_tags:
        for sound in extract_sound_files(sound_tags):
            segments.append({"type": "sound", "value": sound})

    return segments 

def segment_instructions(instruction_text):
    segments = []
    lines = instruction_text.strip().split('\n')

    for line in lines:
        sound_match = re.match(r"<sound:(.+)>", line.strip())
        if sound_match:
            segments.append({
                "type": "sound",
                "value": sound_match.group(1).strip()
            })
        else:
            segments.append({
                "type": "text",
                "value": line.strip()
            })

    return segments


@app.route('/next-phase', methods=['POST'])
def next_phase():
    data = request.get_json()
    choice = data.get("choice")
    current_phase = session.get("current_phase", 0)
    
    if choice and choice.startswith("(B)"):
        next_phase = current_phase  # repeat same
    else:
        next_phase = current_phase + 1

    session["current_phase"] = next_phase

    app_id = detect_app_id_from_port(request.host)

    phase_data = get_next_part(app_id=app_id, phase=next_phase)
    if not phase_data:
        return jsonify({"error": "Phase not found"}), 404

    section_label = phase_data.get('section_label', 'UNKNOWN').strip()
    combined_text = f"{section_label}\n{phase_data['instruction_text']}" if section_label else phase_data['instruction_text']


    return jsonify({
        "app_id": app_id,  # 👈 Add this line!
        "phase": next_phase,
        "segmentedInstructions": segment_instructions(combined_text),
        "feedbackRequest": phase_data.get("feedbackRequest_text") or "",
        "questions": [
            {"choice": line[:3].strip(), "text": line.strip()}
            for line in phase_data["question_text"].split("\n") if line.strip()
        ],
        "soundFiles": extract_sound_files(combined_text),
        "ai_prompt_id": phase_data["ai_prompt_id"],
        "is_last_phase": (next_phase == get_max_phase(app_id))
    })


@app.route('/feedback', methods=['POST'])
def feedback():
    data = request.get_json()
    feedback_text = data.get('feedback', '')
    recommendation = get_chatgpt_recommendation(feedback_text)
    return jsonify({"recommendation": recommendation})

def get_chatgpt_recommendation_XXXXX(feedback):
    try:
        app_id = 1
        phase = session.get("current_phase", 0)

        phase_data = get_next_part(app_id, phase)
        prompt_name = phase_data.get("prompt_template_name")

        if prompt_name:
            messages = get_prompt_messages_by_template_name(prompt_name)
        else:
            logging.warning("Missing prompt_template_name. Falling back to rule-based recommendation.")
            return get_recommendation(feedback)

        messages.append({
            "role": "user",
            "content": feedback
        })

        client = OpenAI()
        completion = client.chat.completions.create(
#       completion = openai.ChatCompletion.create(
            model="gpt-4",
            messages=messages
        )

        return completion.choices[0].message.content.strip()

    except Exception as e:
        logging.error(f"OpenAI error: {e}")
        return get_recommendation(feedback)
    

def store_feedback(tenant_id, user_id, session_id, app_id, phase_number, feedbacktext):
    conn = MySQLdb.connect(
        host="localhost",
        user="openai_user",
        passwd="IOyg76H2l%252BewRX2xhsDJAo7qnfVDHtx9RB%253D%",  # replace or load via env var
        db="openai_prompts",
        charset="utf8mb4"
    )
    cursor = conn.cursor()
    cursor.execute("""
        INSERT INTO session_feedback (tenant_id, user_id, session_id, app_id, phase_number, feedbacktext)
        VALUES (%s, %s, %s, %s, %s, %s)
    """, (tenant_id, user_id, session_id, app_id, phase_number, feedbacktext))
    conn.commit()
    conn.close()

def store_summary(session_id, phase_number, summary):
    conn = MySQLdb.connect(
        host="localhost",
        user="openai_user",
        passwd="IOyg76H2l%252BewRX2xhsDJAo7qnfVDHtx9RB%253D%",
        db="openai_prompts",
        charset="utf8mb4"
    )
    cursor = conn.cursor()
    cursor.execute("""
        UPDATE session_feedback
        SET summary = %s
        WHERE session_id = %s AND phase_number = %s
        ORDER BY id DESC
        LIMIT 1
    """, (summary, session_id, phase_number))
    conn.commit()
    conn.close()   
    

def get_chatgpt_recommendation(feedback):
    try:
        app_id = 2
        phase = session.get("current_phase", 0)
        logging.info(f"🧠 Getting GPT recommendation for phase {phase}, app_id {app_id}")

        phase_data = get_next_part(app_id, phase)
        logging.info(f"🔎 Phase data fetched: {phase_data}")
        if not phase_data:
            logging.error(f"❌ No phase data found for app_id={app_id}, phase={phase}")
            return get_recommendation(feedback)

        prompt_name = phase_data.get("prompt_template_name")
        if not prompt_name:
            logging.warning("⚠️ Missing prompt_template_name. Falling back to rule-based recommendation.")
            return get_recommendation(feedback)

        messages = get_prompt_messages_by_template_name(prompt_name)
        if not messages:
            logging.warning(f"⚠️ No messages found for prompt template '{prompt_name}'. Falling back.")
            return get_recommendation(feedback)

        # Log the prompt messages before sending
        logging.debug(f"📨 Prompt messages before adding user input:\n{messages}")

        messages.append({
            "role": "user",
            "content": feedback
        })

        logging.debug(f"📡 Sending messages to OpenAI:\n{messages}")

        client = OpenAI()
        completion = client.chat.completions.create(
#       completion = openai.ChatCompletion.create(
            model="gpt-4",
            messages=messages
        )

        response = completion.choices[0].message.content.strip()
        logging.info("✅ GPT recommendation received.")
        return response

    except Exception as e:
        logging.error(f"🔥 OpenAI error in get_chatgpt_recommendation: {e}")
#        logging.error(f"Second: Error in get_chatgpt_recommendation: {traceback.format_exc()}")
        return get_recommendation(feedback)


@app.route('/phases', methods=['GET'])
def get_phase_labels():
    try:
        app_id = detect_app_id_from_port(request.host)  # You already have this logic

        conn = MySQLdb.connect(
            host="localhost",
            user="openai_user",
            passwd="IOyg76H2l%252BewRX2xhsDJAo7qnfVDHtx9RB%253D%",
            #passwd=db_password,
            db="openai_prompts",
            #db="openai_prompts",
            charset="utf8mb4"
        )

        cursor = conn.cursor(MySQLdb.cursors.DictCursor)

        cursor.execute("""
            SELECT phase_number, section_label
            FROM phase_content
            WHERE app_id = %s
            ORDER BY phase_number ASC
        """, (app_id,))
        results = cursor.fetchall()

        return jsonify(results)

    except Exception as e:
        logging.error(f"Error fetching phase labels: {e}")
        return jsonify([]), 500
 

def get_summary_from_openai(text):
    messages = [
        {"role": "system", "content": "Summarize the following user text into 2-3 crisp bullet points capturing the emotional or mental themes. Keep it short and human-friendly."},
        {"role": "user", "content": text}
    ]
    client = OpenAI()
    completion = client.chat.completions.create(
#    completion = openai.ChatCompletion.create(
        model="gpt-4",
        messages=messages,
        temperature=0.7
    )
    return completion.choices[0].message.content.strip()    


#with a lot of logging
@app.route('/submit-feedback', methods=['POST'])
def submit_feedback():
    try:
        data = request.get_json()
        if data is None:
            logging.error("No JSON data received in /submit-feedback.")
            return jsonify({"error": "No data received"}), 400

        tenant_id = data.get("tenant_id", 1)
        user_id = data.get("user_id", 1)
        session_id = data.get("session_id", str(uuid.uuid4()))
        session["session_id"] = session_id
        app_id = detect_app_id_from_port(request.host)
        phase = data.get("phase")
        feedback_text = data.get("feedback")

        if phase == 2:
            # ✅ Store feedback only for phase 2
            store_feedback(tenant_id, user_id, session_id, app_id, phase, feedback_text)
            logging.info(f"📝 Storing feedback: tenant_id={tenant_id}, user_id={user_id}, session_id={session_id}, app_id={app_id}, phase={phase}, feedback={feedback_text}")

            # ✅ Generate summary
            summary = get_summary_from_openai(feedback_text)
            return jsonify({ "summary": summary })
        else:
            recommendation = get_recommendation(feedback_text)
            return jsonify({ "recommendation": recommendation })

    except Exception as e:
        logging.error(f"🔥 Error in /submit-feedback: {e}")
        return jsonify({"error": "Server error"}), 500
    

@app.route('/confirm-summary', methods=['POST'])
def confirm_summary():
    data = request.get_json()
    phase = data.get("phase")
    summary = data.get("summary")
    session_id = session.get("session_id")
     
    # Store the summary only after user confirmed
    store_summary(session_id, phase, summary)
    logging.info(f"✅ Storing summary: session_id={session_id}, phase={phase}, summary={summary}")

    return jsonify({"status": "summary confirmed"})


# === Main entrypoint ===
#if __name__ == '__main__':
#    app.run(host='0.0.0.0', port=5001, debug=True)

if __name__ == '__main__':
    app.run(
        host='0.0.0.0',
        port=5001,
        ssl_context=(
            '/var/www/html/decompression/certs/fullchain.pem',
            '/var/www/html/decompression/certs/privkey.pem'
        ),
        debug=True
    )
    
