import os
import re
import uuid
import logging
import json
import sys
import random
import pprint
from openai import OpenAI
print("📍 being here 1", flush=True)
from dotenv import load_dotenv
from flask import Flask, request, jsonify
from openai import OpenAI
from db import SessionLocal, init_db
# import models
from utils.prompt_manager import build_messages_payload
from models import Session as ChatSession, User, Case
from models import Message
from models import Document
from flask import render_template
from models import Topic
from sqlalchemy.sql import func

client = OpenAI()  # Uses env var OPENAI_API_KEY automatically

load_dotenv()

print(f"🔑 OPENAI_API_KEY ends with: ...{os.getenv('OPENAI_API_KEY')[-4:]}")
print(f"🗄 DB user: {os.getenv('DB_USER')}")

openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

app = Flask(__name__)

init_db()  # ← now creates *all* tables from models.py

# @app.route("/")
# def hello():
#    return "✅ Dynbot backend is running."

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

@app.route("/init-session", methods=["POST"])
def init_session():
    db = SessionLocal()
    data = request.get_json()

    tenant_id = data.get("tenant_id", 1)
    user_id = data.get("user_id", 1)
    session_token = data.get("session_token", str(uuid.uuid4()))

    # Ensure user exists
    user = db.query(User).filter_by(id=user_id).first()
    if not user:
        user = User(id=user_id, tenant_id=tenant_id, username="Default User", email="default@example.com")
        db.add(user)
        db.commit()

    # Always create a new session
    new_session = ChatSession(
        tenant_id=tenant_id,
        user_id=user_id,
        session_token=session_token,
    )
    db.add(new_session)
    db.commit()
    db.refresh(new_session)

    # Create a case before closing the session
    case = Case(
        tenant_id=tenant_id,
        user_id=user_id,
        session_id=new_session.id
    )
    db.add(case)
    db.commit()
    db.refresh(case)

    # ✅ Access attributes before db.close()
    response = {
        "session_id": new_session.id,
        "session_token": session_token,
        "case_id": case.id
    }

    db.close()
    return jsonify(response)


@app.route("/cases", methods=["POST"])
def create_case():
    db = SessionLocal()
    tenant_id = request.json.get("tenant_id", 1)  # default tenant
    new = models.Case(tenant_id=tenant_id, title=request.json.get("title",""))
    db.add(new); db.commit(); db.refresh(new)
    db.close()
    return jsonify({"case_id": new.id}), 201

@app.route("/cases/<int:case_id>/history", methods=["GET"])
def get_history(case_id):
    db = SessionLocal()
    msgs = db.query(models.Message).filter_by(case_id=case_id).order_by(models.Message.timestamp).all()
    fups = db.query(models.FollowupQuestion).join(models.Message).filter(models.Message.case_id==case_id).all()
    db.close()
    return jsonify({
        "messages": [{"role":m.role,"content":m.content,"timestamp":m.timestamp.isoformat()} for m in msgs],
        "followups": [{"message_id":f.message_id,"question_text":f.question_text} for f in fups]
    })

@app.route("/cases/<int:case_id>/messages", methods=["POST"])
def post_message(case_id):
    db = SessionLocal()
    data = request.get_json()

    user_text = data.get("content")
    button_choice = data.get("button_choice", "")  # fallback to empty string
    tenant_id = data.get("tenant_id", 1)

    if not user_text or not tenant_id:
        db.close()
        return jsonify({"error": "Missing 'content' or 'tenant_id' in request"}), 400

    # 1) Store user message
    user_msg = Message(case_id=case_id, role="user", content=user_text, button_choice=button_choice)
    db.add(user_msg)
    db.commit()
    db.refresh(user_msg)

    # 2) Build prompt payload
    messages_payload = build_messages_payload(db, case_id, tenant_id)

    # 3) Call OpenAI Chat API with tool function for follow-ups
    resp = openai_client.chat.completions.create(
        model="gpt-4o-mini",
        messages=messages_payload,
        tools=[
            {
                "type": "function",
                "function": {
                    "name": "extract_followups",
                    "description": "Suggest 2–4 follow-up questions based on the assistant's reply.",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "questions": {
                                "type": "array",
                                "items": { "type": "string" }
                            }
                        },
                        "required": ["questions"]
                    }
                }
            }
        ],
        tool_choice="auto"
    )

    pprint.pprint(resp)
    choice = resp.choices[0]

    if choice.finish_reason == "tool_calls":
        tool_call = choice.message.tool_calls[0]
        args = json.loads(tool_call.function.arguments)
        followups = args.get("questions", [])
        if choice.message.content:
            ai_text = choice.message.content
        else:
            # fallback if OpenAI didn’t return direct message content (typical in tool call)
            ai_text = "Vielen Dank für Ihre Auswahl. Hier sind mögliche nächste Schritte oder Zusammenfassungen."
        #ai_text = choice.message.content or "(no text reply provided)"
    else:
        ai_text = choice.message.content
        followups = []

    # 4) Truncate to max 3 bullet points if present
    if ai_text:
        lines = ai_text.split("\n")

        # Match lines that start with a number and a dot, e.g., "1. ", "2. "
        numbered_lines = [line for line in lines if re.match(r"^\d+\.\s", line)]

        if numbered_lines:
            first_numbered_index = next(
                (i for i, line in enumerate(lines) if re.match(r"^\d+\.\s", line)), None
            )
            if first_numbered_index is not None:
                truncated = numbered_lines[:3]
                # Keep all lines before the first numbered point
                prefix = lines[:first_numbered_index]
                ai_text = "\n".join(prefix + truncated)

    # 5) Extract and truncate bold headings as choices (max 3)
    choices = re.findall(r"\*\*(.*?)\*\*", ai_text)
    # choices = choices[:3]
    if len(choices) > 3:
        choices = random.sample(choices, 3)  # ✅ picks 3 unique items at random

    # 6) Store assistant's reply
    ai_msg = Message(case_id=case_id, role="assistant", content=ai_text)
    db.add(ai_msg)
    db.commit()
    db.refresh(ai_msg)

    past_messages = db.query(Message).filter_by(case_id=case_id).order_by(Message.timestamp).all()
    turn = len([m for m in past_messages if m.role == "user"])
    is_summary = (turn == 3)

    # ✅ Only personalize if this is the summary phase
    if is_summary:
        intro_doc = db.query(Document).filter_by(tenant_id=tenant_id, title="summary_intro_1").first()

        print("📄 Before quote call:", flush=True)
        quotes = db.query(Document).filter_by(tenant_id=tenant_id, title="quote").all()
        print("📄 After quote call:", flush=True)
        intro_text = intro_doc.content if intro_doc else ""
        # quote_text = random.choice(quotes).content if quotes else ""

        print("📄 Loaded quote entries:", quotes, flush=True)
        for q in quotes:
            print("↪️ Quote:", q.content, flush=True)

        quote_text = ""
        if quotes:
            try:
                quote_text = random.choice(quotes).content
            except Exception as e:
                print("❌ Failed to select quote:", e, flush=True)

        user_msgs = [m.content for m in past_messages if m.role == "user"]
        button_choices = [m.button_choice for m in past_messages if m.role == "user"]
        print("User Messages:", button_choices, flush=True)
        # button_choice_1 = user_msgs[0] if len(user_msgs) > 0 else ""
        # button_choice_2 = user_msgs[1] if len(user_msgs) > 1 else ""
        # button_choice_3 = user_msgs[2] if len(user_msgs) > 2 else ""
        button_choice_1 = button_choices[0] if len(button_choices) > 0 else ""
        button_choice_2 = button_choices[1] if len(button_choices) > 1 else ""
        button_choice_3 = button_choices[2] if len(button_choices) > 2 else ""

        intro_filled = intro_text.format(
            iteration1=button_choice_1,
            iteration2=button_choice_2,
            iteration3=button_choice_3
        )

        print("User Choices:", button_choice_1, button_choice_2, button_choice_3, flush=True)


        # ✅ Now wrap the AI response
        ai_text = f"{intro_filled}\n\n{ai_text}\n\n👉 {quote_text}"

        print("🔖 Final personalized summary constructed", flush=True)

    print("📍 Status of is_summary", is_summary, flush=True)

    db.close()

    return jsonify({
        "reply": ai_text,
        "followups": followups,
        "choices": choices,
        "is_summary": is_summary
    })


@app.route("/tenants", methods=["POST"])
def create_tenant():
    db = SessionLocal()
    name = request.json["name"]
    t = models.Tenant(name=name)
    db.add(t); db.commit(); db.refresh(t)
    db.close()
    return jsonify({"tenant_id": t.id}), 201


@app.route("/topics/random", methods=["GET"])
def get_random_topics():
    db = SessionLocal()
    tenant_id = 1  # or dynamic if implemented
    raw_topics = db.query(Topic)\
        .filter_by(tenant_id=tenant_id)\
        .order_by(func.random())\
        .limit(3)\
        .all()

    # Replace {topic} in question field
    results = []
    for t in raw_topics:
        filled_question = t.question.replace("{topic}", t.topic)
        results.append({
            "topic": t.topic,
            "question": filled_question
        })

    db.close()
    return jsonify(results)    


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

