import os
import re
import time
import json
import base64
import io
import uuid
import httpx
import requests
import asyncio as asyncico
from typing import Optional, Dict
from google import genai
from google.genai import types
from PIL import Image
from fastapi import Body, Header
from fastapi.templating import Jinja2Templates
from fastapi import FastAPI, WebSocket, Depends, HTTPException, Form, UploadFile, File, Query, Form, status, Request
from fastapi.responses import HTMLResponse, RedirectResponse, JSONResponse
from dotenv import load_dotenv
from utils1 import first_prompt, feedback_prompt
from gtts import gTTS
from io import BytesIO
from fastapi.staticfiles import StaticFiles
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from datetime import datetime
from sqlalchemy import Column, Integer, String, DateTime
from typing import Generator, Optional
from datetime import datetime
from fastapi.security import OAuth2PasswordRequestForm
# import bcrypt
from fastapi.middleware.cors import CORSMiddleware
from auth2 import get_current_user
from helper_functions import *
from index_page import home_page
# from google.generativeai.types import content_types
# auth implementation imports
from routers import auth, dictation, quiz
from schemas.user import UserBase
from utils.jwt import verify_token
from re_usable_function_tts import generate_tts_base64_audio
app = FastAPI(title="Interactive Learning App")
load_dotenv()
app.mount("/static", StaticFiles(directory="static"), name="static")

origins = ["*"]
VOICES = {
    "male": "en-IN-Standard-F",
    "female": "en-IN-Standard-D"
          }
app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
app.include_router(auth.router)
app.include_router(dictation.router)
app.include_router(quiz.router)

templates = Jinja2Templates(directory="templates")

# Configure Gemini API
GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY")
if not GOOGLE_API_KEY:
    raise ValueError("GOOGLE_API_KEY environment variable not set")

# genai.configure(api_key=GOOGLE_API_KEY)

# base url of django API
DJANGO_API_BASE = os.getenv("DJANGO_API_BASE")

# Using gemini-1.5-flash for its multi-modal capabilities and cost-effectiveness
# g_model = genai.GenerativeModel('gemini-2.5-flash')
LLM_MODEL = 'gemini-2.5-flash'
g_model = genai.Client(api_key=GOOGLE_API_KEY)
sessions = {}


# ============================================
# Django Session Management Helper Functions
# ============================================

async def get_session_from_django(client_id: str, token: str) -> Optional[dict]:
    """
    Get session from Django MySQL database
    
    Args:
        client_id: Unique client identifier
        token: JWT authentication token
        
    Returns:
        Session data dict or None if not found
    """
    try:
        async with httpx.AsyncClient() as client:
            response = await client.get(
                f"{DJANGO_API_BASE}/user/session/{client_id}/",
                headers={"Authorization": f"Bearer {token}"},
                timeout=10.0
            )
            
            if response.status_code == 200:
                data = response.json()
                if data.get('exists'):
                    print(f"📦 Session loaded from Django MySQL: {client_id}")
                    return data.get('data')
            
            elif response.status_code == 404:
                print(f"🔍 Session not found in Django: {client_id}")
                return None
            
            else:
                print(f"⚠️ Django session GET failed: {response.status_code}")
                # Fallback to in-memory
                return sessions.get(client_id)
    
    except httpx.TimeoutException:
        print(f"⏱️ Django session GET timeout for {client_id}, using fallback")
        return sessions.get(client_id)
    
    except Exception as e:
        print(f"❌ Error fetching session from Django: {e}")
        # Fallback to in-memory
        return sessions.get(client_id)

async def save_session_to_django(client_id: str, session_data: dict, token: str) -> bool:
    """
    Save session to Django MySQL database
    
    Args:
        client_id: Unique client identifier
        session_data: Complete session state dictionary
        token: JWT authentication token
        
    Returns:
        True if saved successfully, False otherwise
    """
    try:
        async with httpx.AsyncClient() as client:
            print("POSTing to:", f"{DJANGO_API_BASE}/user/session/save/")
            response = await client.post(
                f"{DJANGO_API_BASE}/user/session/save/",
                json={
                    'client_id': client_id,
                    'session_data': session_data
                },
                headers={
                    "Authorization": f"Bearer {token}",
                    "Content-Type": "application/json"
                },
                timeout=10.0
            )
            
            if response.status_code in [200, 201]:
                result = response.json()
                action = "created" if result.get('created') else "updated"
                print(f"💾 Session {action} in Django MySQL: {client_id}")
                return True
            else:
                print(f"⚠️ Failed to save session to Django: {response.status_code}")
                print(f"   Response: {response.text}")
                # Fallback to in-memory
                sessions[client_id] = session_data
                return False
    
    except httpx.TimeoutException:
        print(f"⏱️ Django session SAVE timeout for {client_id}, using fallback")
        sessions[client_id] = session_data
        return False
    
    except Exception as e:
        print(f"❌ Error saving session to Django: {e}")
        # Fallback to in-memory
        sessions[client_id] = session_data
        return False

async def delete_session_from_django(client_id: str, token: str) -> bool:
    """
    Delete session from Django (for reset)
    
    Args:
        client_id: Unique client identifier
        token: JWT authentication token
        
    Returns:
        True if deleted successfully, False otherwise
    """
    try:
        async with httpx.AsyncClient() as client:
            response = await client.delete(
                f"{DJANGO_API_BASE}/user/session/{client_id}/delete/",
                headers={"Authorization": f"Bearer {token}"},
                timeout=10.0
            )
            
            if response.status_code == 200:
                result = response.json()
                if result.get('deleted'):
                    print(f"🗑️ Session deleted from Django MySQL: {client_id}")
                else:
                    print(f"ℹ️ Session not found in Django (already deleted): {client_id}")
                return True
            else:
                print(f"⚠️ Failed to delete session from Django: {response.status_code}")
                return False
    
    except Exception as e:
        print(f"❌ Error deleting session from Django: {e}")
        return False
    
    finally:
        # Always delete from in-memory fallback
        if client_id in sessions:
            del sessions[client_id]
            print(f"🗑️ Session deleted from in-memory fallback: {client_id}")

def session_exists_in_memory(client_id: str) -> bool:
    """
    Check if session exists in local memory (fallback check)
    
    Args:
        client_id: Unique client identifier
        
    Returns:
        True if session exists in memory
    """
    return client_id in sessions



@app.get("/unauthorized/{error}", response_class=HTMLResponse)
async def get_login_page(request: Request, error: str = None):
    token = request.cookies.get("access_token")
    error = error if error else "Unauthorized access"
    
    if token:
        payload = verify_token(token)
        if payload:
            return RedirectResponse(url="/home", status_code=302)
    
    return templates.TemplateResponse("unauthorized.html", {"request": request, 'error': error})

@app.get("/", response_class=HTMLResponse)
async def get_login_page(request: Request):
    token = request.cookies.get("access_token")
    
    if token:
        payload = verify_token(token)
        if payload:
            return RedirectResponse(url="/home", status_code=302)
    
    return templates.TemplateResponse("login.html", {"request": request})

@app.get("/invite/{invite_code}/", response_class=HTMLResponse)
async def invite_login(request: Request, invite_code: str):
    # invite_code = str(invite_code.strip().upper())
    invite_code = '2025ABCD'
    
    return RedirectResponse(url=f"/auth/google/login/{invite_code}")
    
@app.get("/home", response_class=HTMLResponse)
async def home_page(request: Request, current_user: UserBase = Depends(auth.get_current_user)):
    # ", current_user: UserBase = Depends(auth.get_current_user)"

    """
    Renders the home page, accessible only after successful authentication.
    The current_user object will contain details of the authenticated user.
    """

    # You can pass user data to the template
    token = request.cookies.get("access_token")
    
    if not token:
        return RedirectResponse(url="/", status_code=302)
        
    # payload = verify_token(token)
    # if not payload:
    #     return RedirectResponse(url="/", status_code=302)
    
    
    return templates.TemplateResponse("home.html", {
        "request": request,
        "user": current_user,
        "access_token": token,
    })


@app.get("/dictation-practice", response_class=HTMLResponse)
async def dictation_practice_page(request: Request, current_user: UserBase = Depends(auth.get_current_user)):
    token = request.cookies.get("access_token")
    if not token:
        return RedirectResponse(url="/", status_code=302)
    
    return templates.TemplateResponse("dictation.html", {
        "request": request,
        "user": current_user,
        "access_token": token,
        "access_token": token,
    })

@app.get("/quiz-practice", response_class=HTMLResponse)
async def quiz_practice_page(request: Request, current_user: UserBase = Depends(auth.get_current_user)):
    token = request.cookies.get("access_token")
    if not token:
        return RedirectResponse(url="/", status_code=302)
    
    return templates.TemplateResponse("quiz.html", {
        "request": request,
        "user": current_user,
        "access_token": token,
    })


@app.post("/chat/")
async def chat_endpoint(
    request: Request,
    current_user: UserBase = Depends(auth.get_current_user),
    client_id: str = Form(...),
    language: str = Form(...),
    content: UploadFile = File(...),
    message_type: str = Form(...),
    mode: str = Form(...),
    voice: str = Form(...),
    model: str = Form(...),
    access_token: Optional[str] = Form(None)
):
    
    # --- Authentication ---
    token = None
    auth_header = request.headers.get("Authorization")
    
    if auth_header and auth_header.startswith("Bearer "):
        token = auth_header.split(" ")[1]
    if not token:
        token = request.cookies.get("access_token")
    if not token:
        token = access_token
    
    if not token:
        return RedirectResponse(url="/", status_code=302)
        
    payload = verify_token(token)
    if not payload:
        return RedirectResponse(url="/", status_code=302)
    
    add_condetion = False
    
    session = await get_session_from_django(client_id, token)
    if session is None:
        # Create new session
        session = {
            "trial_start_time": time.time(),
            "interaction_count": 0,
            "is_first_message": True,
            "learning_history": [],
            "incorrect_answers": 0,
            "conversation_id": None,
            "difficulty_level": "medium",
            "correct_answers": 0,
            "current_score": 0,
            "user_id": None,
            "first_response": None,
            "continution": None,
            "reset": None,
            "last_question": "",
            "previous_question": "",
            "last_response": "",
            "last_interaction_time": None,
            "message_id": None,
            "previous_message_id": None,
            "question_stored": False,
        }
        print(f"🆕 New session created: {client_id}")
        
        # Save immediately to Django
        await save_session_to_django(client_id, session, token)
    else:
        print(f"♻️ Existing session loaded: {client_id} (interaction: {session.get('interaction_count', 0)})")
    # --- Session Initialization ---
    # if client_id not in sessions:
    #     sessions[client_id] = {
    #         "trial_start_time": time.time(),
    #         "interaction_count": 0,
    #         "is_first_message": True,
    #         "learning_history": [],
    #         "incorrect_answers": 0,
    #         "conversation_id": None,
    #         "difficulty_level": "medium",
    #         "correct_answers": 0,
    #         "current_score": 0,
    #         "user_id": None,
    #         "first_response": None,
    #         "continution": None,
    #         "reset": None,
    #         "last_question": "",
    #         "previous_question": "",
    #         "last_response": "",
    #         "last_interaction_time": None,
    #         "message_id": None,
    #         "previous_message_id": None,
    #         "question_stored": False,
        # }
    
    # session = sessions[client_id]
    
    # token_checker = TokenUsageChecker()
    # is_limit_end = await token_checker.check_token_limit(token)
    token_limit_function = await get_user_today_token_usage(token)
    token_info = token_limit_function.get('daily_tokens', 0)
    print(f'loggedin {client_id} - user: {current_user} token used {token_info}')
    # print(is_limit_end.get('can_proceed'))
    # print(is_limit_end.get('current_usage'))
    
    
    # token_info = await get_user_today_token_usage(token)
    # print(token_info['daily_tokens'])
    
    if token_info > 100000:
        return {
            "gemini_response": f"You have exceeded your daily token limit: 100000 and used : {token_info}. Please try again tomorrow.",
            "message_id": None,
            "audio_base64": None,
        }
    # print(f'token info: {token_info}')
    
    # --- Read uploaded content ONCE at the start ---
    file_bytes = await content.read()
    
    # Validate file content
    if not file_bytes:
        return {"message": "Gemini: error - No file content received."}
    
    mime_type = content.content_type
    if not mime_type:
        mime_type = detect_file_type(file_bytes)
    file_name = content.filename
    
    
    # --- Check for continuation (every 3 interactions) ---
    if session["interaction_count"] > 0 and session["interaction_count"] % 2 == 0:
        # session["continution"] = file_bytes  # Store the bytes
        
        add_condetion = True
    else:
        add_condetion = False

       
    
    # --- Create conversation if first message ---
    if session["is_first_message"]:
        print('creating conversation')
        
        async with httpx.AsyncClient() as client:
            try:
                conv_response = await client.post(
                    f"{DJANGO_API_BASE}/create-conversation/", 
                    headers={"Authorization": f"Bearer {token}"},
                    
                )
                print(f'conversation response: {conv_response.status_code}')
                
                if conv_response.status_code == 201:
                    conversation = conv_response.json()
                    session["conversation_id"] = conversation["id"]
                    session["is_first_message"] = False
                else:
                    return {"message": f"Gemini: error - Failed to create conversation. Status: {conv_response.status_code}"}
            except Exception as e:
                print(f"Conversation creation error: {str(e)}")
                return {"gemini_response": f"Gemini: error - Failed to create conversation: {str(e)}"}

    
    
    # Initialize main_content
    main_content = session.get("first_response", "")
    
    # --- Store user message ---
    async with httpx.AsyncClient() as client:
        if message_type in ["file", "audio"]:
            
            # Create FRESH BytesIO for Gemini
            gemini_file_obj = io.BytesIO(file_bytes)
            gemini_file_obj.name = file_name
            gemini_file_obj.content_type = mime_type

            try:
               
                uploaded_file = g_model.files.upload(
                    file=gemini_file_obj,
                    config={
                        'display_name': f"User uploaded {file_name}",
                        'mime_type': mime_type
                        }
                    )
                input_to_gemini = [uploaded_file]
                print('file uploaded to Gemini successfully')
            except Exception as e:
                print('file upload to gemini exception is working')
                print(f"Gemini upload error: {str(e)}")
                return {"gemini_response": f"Gemini: error - File processing for Gemini failed: {str(e)}"}
            finally:
                gemini_file_obj.close()
            
            # Prepare SEPARATE file for Django API
            files = {
                "file": (file_name, file_bytes, mime_type)
            }
            data = {
                "sender": "user",
                "conversation_id": str(session["conversation_id"])
            }
            
            try:
                msg_response = await client.post(
                    f"{DJANGO_API_BASE}/create-message/",
                    files=files,
                    data=data,
                    headers={"Authorization": f"Bearer {token}"},
                    timeout=120.0
                )
    
            except Exception as e:
                print(f"Django message store error: {str(e)}")
                return {"gemini_response": f"Gemini: error - Failed to store message: {str(e)}"}
                
        else:
    
            text_content = file_bytes.decode("utf-8").strip()
            input_to_gemini = [text_content]
            
            # Handle reset request
            
            
            # Set main_content for subsequent interactions
            if session["interaction_count"] > 0:
                main_content = session.get("first_response", "")

            
            try:
                msg_response = await client.post(
                    f"{DJANGO_API_BASE}/create-message/",
                    json={
                        "sender": "user",
                        "content": text_content,
                        "conversation_id": session["conversation_id"]
                    },
                    headers={"Authorization": f"Bearer {token}"},
                    timeout=120.0
                )
            
            except Exception as e:
                print(f"Django message store error: {str(e)}")
                return {"gemini_response": f"Gemini: error - Failed to store message: {str(e)}"}

        if msg_response.status_code not in [200, 201]:
            return {"gemini_response": f"Gemini: error - Failed to store user message. Status: {msg_response.status_code}"}

    # --- Generate Gemini response ---
    
    if session["interaction_count"] == 0:
        prompt = first_prompt(mode, input_to_gemini, language=language)
    else:
        prompt = feedback_prompt(
            main_content,
            mode,
            input_to_gemini,
            session.get("last_question", ""),
            session.get("last_response", ""),
            session["learning_history"],
            language=language
        )
    
    
    try:
        
        response = g_model.models.generate_content(model=LLM_MODEL,contents = prompt)
        asyncico.create_task(count_token_and_store(response, token=token))
        print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
        # print(f'thoughts_token: {thoughts}')
        # print(f'prompt_tokens: {prompt}')
        # print(f'output_tokens: {output}')
        # print(f'total_tokens: {total}')
        # print("******************************************************")
        gemini_response = response.text
        
    except Exception as e:
        print(f"Gemini generation error: {str(e)}")
        return {"gemini_response": f"Gemini: error - Response generation failed: {str(e)}"}
    
    # Store first response for future reference
    if session["interaction_count"] == 0:
        session["first_response"] = gemini_response
        print('first response stored in session')

    # --- Store Gemini bot response ---
    
    async with httpx.AsyncClient() as client:
        try:
            bot_msg_response = await client.post(
                f"{DJANGO_API_BASE}/create-message/",
                json={
                    "sender": "bot",
                    "content": gemini_response,
                    "conversation_id": session["conversation_id"]
                },
                headers={"Authorization": f"Bearer {token}"},
                timeout=12.0
            )
            
            if bot_msg_response.status_code not in [200, 201]:
                return {"gemini_response": f"Gemini: error - Failed to store Gemini reply. Status: {bot_msg_response.status_code}"}
            
            message_id = bot_msg_response.json()['id']
            session["previous_message_id"] = session["message_id"]
            session["message_id"] = message_id
            print(f'bot message stored with id: {message_id}')
        except Exception as e:
            print(f"Bot message store error: {str(e)}")
            return {"gemini_response": f"Gemini: error - Failed to store bot message: {str(e)}"}
    
    
    # --- Update session state ---
    session["previous_question"] = session["last_question"]
    session["last_question"] = extract_last_question(gemini_response)
    
  
    is_correct = None
    if session["interaction_count"] >= 1:
        is_correct = is_answer_correct(gemini_response) if session["last_question"] != "" else None
        if is_correct:
            session["correct_answers"] += 1
            session["current_score"] = 1
        else:
            session["incorrect_answers"] += 1
            session["current_score"] = 0

    
    session["last_response"] = gemini_response
    session["interaction_count"] += 1
    session["last_interaction_time"] = time.time()

    # Track answer correctness
    
    print(f'you answer is corroct? {is_correct}')
    print('process completed')
    
    # --- TTS output ---
    print('generating audio')
    if session["question_stored"]:
        if message_type in ["file", "audio"]:
            text_content = "User Input is A File/Audio Content"

        score_stored = update_latest_question_answer(token, session["conversation_id"], session["previous_message_id"], text_content, is_correct, session["current_score"])
        
        print(score_stored)
    question_stored = create_question_answer(token, session["conversation_id"], message_id, session["last_question"])
    
    print(question_stored)
    if question_stored.status_code == 201:
        session["question_stored"] = True
    

    audio_base64 = None
    try:
        # audio_data = await generate_tts_audio(gemini_response, lang=language)
        print(voice)
        audio_base64 = generate_tts_base64_audio(text_to_speak=gemini_response, voice_name=voice, language=language)
        if not audio_base64:
            audio_data = await generate_tts_audio(gemini_response, lang=language)
            audio_base64 = base64.b64encode(audio_data).decode('utf-8')
        print('audio generated successfully')
    except Exception as e:
        print(f"TTS error: {str(e)}")
        # Continue without audio on error
    print("---------------------------------------------------------------")
    print(f'Score = ----------{session["correct_answers"]}----------------')
    print("---------------------------------------------------------------")
    save_success = await save_session_to_django(client_id, session, token)
    if not save_success:
        print(f"⚠️ Session saved to in-memory fallback only for {client_id}")
    return {
        "gemini_response": gemini_response,
        "message_id": message_id,
        "audio_base64": audio_base64,
        "score": session["correct_answers"],
        "add_condetion": add_condetion,
    }


@app.get("/logout")
async def logout(response: HTMLResponse): # Can also be a JSONResponse if your frontend handles it
    """Logs out the user by clearing the access token cookie and redirects to login."""
    
    logout_response = RedirectResponse(url="/", status_code=status.HTTP_302_FOUND)
    logout_response.delete_cookie(key="access_token", path="/")
    return logout_response

# feedback endpoint
from pydantic import BaseModel

class FeedbackPayload(BaseModel):
    message_id: int
    liked: bool
    disliked: bool
    feedback: str | None = None
    access_token: str | None = None

@app.post("/api/feedback/")
async def save_feedback(request: Request, 
    payload: FeedbackPayload,
    current_user: UserBase = Depends(auth.get_current_user),
):
    print('processing feedback')
    auth_header = request.headers.get("Authorization")
    token = None
    if auth_header and auth_header.startswith("Bearer "):
        token = auth_header.split(" ")[1]
    if not token:
        token = payload.access_token
    
    # If the token isn't in the payload, try to get it from the cookies (for web clients)
    if token is None:
        token = request.cookies.get("access_token")
    
    print(f'payload = {payload.message_id}-{payload.liked}- {payload.disliked}')
    print(f'token: {token}')
    
    # Patch the Django message
    async with httpx.AsyncClient() as client:
        dj_response = await client.patch(
            f"{DJANGO_API_BASE}/update-message/{payload.message_id}/",
            json={
                "liked": payload.liked,
                "disliked": payload.disliked,
                "feedback": payload.feedback
            },
            headers={
                "Authorization": f"Bearer {token}"
            }
        )
    
    if dj_response.status_code != 200:
        raise HTTPException(status_code=500, detail="Failed to save feedback to Django")
    print('successful')
    return {"status": "ok"}

@app.get("/admin")
async def admin(response: HTMLResponse):
    
    return RedirectResponse(url=f'{DJANGO_API_BASE}/admin')
        
async def get_access_token_from_header(authorization: Optional[str] = Header(None)) -> str:
    """
    Extracts the JWT string from the 'Authorization: Bearer <token>' header.
    """
    if authorization is None:
        raise HTTPException(status_code=401, detail="Authorization header missing for internal API call")
    
    # Check if the header starts with "Bearer " (case-insensitive check)
    if not authorization.lower().startswith("bearer "):
        raise HTTPException(status_code=401, detail="Invalid authorization scheme. Must be 'Bearer <token>'")
    
    # Return the raw token string
    return authorization.split(" ", 1)[1]
    
async def get_current_mobile_user(token: str = Depends(lambda x: x)): # Mock dependency
    # In your real auth module, this validates the token and returns the user object.
    # We rely on the get_access_token_from_header below to get the raw token string.
    if not token:
        raise HTTPException(status_code=401, detail="Not authenticated")
    # Simulating successful user retrieval
    return UserBase(user_id="user-123")
        
# --- Updated Endpoint ---
@app.post("/api/mobile/feedback") # <-- Path changed
async def save_feedback(
    request: Request,
    payload: FeedbackPayload,
):
    print('processing feedback from mobile')
    print('processing feedback')
    auth_header = request.headers.get("Authorization")
    token = None
    if auth_header and auth_header.startswith("Bearer "):
        token = auth_header.split(" ")[1]
    if not token:
        token = payload.access_token
    
    # We no longer need to check payload or cookies, as the token is guaranteed
    # to be a valid string if the dependencies passed.
    print(f'Authenticated User ID: {current_user.user_id}')
    print(f'Token retrieved from Header (first 10 chars): {token[:10]}...')
    
    # Patch the Django message
    async with httpx.AsyncClient() as client:
        try:
            dj_response = await client.patch(
                f"{DJANGO_API_BASE}/update-message/{payload.message_id}/",
                json={
                    "liked": payload.liked,
                    "disliked": payload.disliked,
                    "feedback": payload.feedback
                },
                headers={
                    # Use the token extracted directly from the header
                    "Authorization": f"Bearer {token}" 
                }
            )
            
            # Check for non-200 responses from the Django API
            if dj_response.status_code != 200:
                # Log the detailed error from Django for debugging
                print(f"Django API Error: {dj_response.status_code} - {dj_response.text}")
                # Raise a 500 but include the Django status code for better insight
                raise HTTPException(
                    status_code=500, 
                    detail=f"Failed to save feedback to Django (status: {dj_response.status_code})"
                )

        except httpx.HTTPError as e:
            # Handle connection errors (e.g., Django service is down)
            print(f"HTTP Connection Error: {e}")
            raise HTTPException(status_code=503, detail="Service temporarily unavailable (Django API unreachable)")
    
    print(f"Feedback saved: {dj_response.json()}")
    return {"status": "ok", "message_id": payload.message_id}

@app.get("/policy", response_class=HTMLResponse)
async def get_login_page(request: Request):        
    return templates.TemplateResponse("policy.html", {"request": request})

# Progress Tracker Functionality
def create_question_answer(token, conversation_id, question_message_id, question_text):
    url = f"{DJANGO_API_BASE}/create-qa/"
    headers = {
        "Authorization": f"Bearer {token}",
    }
    data = {
        "conversation": conversation_id,
        "question_message": question_message_id,
        "question_text": question_text,
    }
    print(f'data to sent the db: {data}')

    response = requests.post(url, data=data, headers=headers)
    return response

def update_latest_question_answer(token, conversation_id, answer_message_id, answer_text, is_correct, score):
    url = f"{DJANGO_API_BASE}/update-latest-qa/"
    headers = {
        "Authorization": f"Bearer {token}",
    }
    data = {
        "conversation_id": conversation_id,
        "answer_message_id": answer_message_id,
        "answer_text": answer_text,
        "is_correct": str(is_correct).lower(),  # true/false as string if needed
        "score": score,
    }
    print(f'answer data: {data}')

    response = requests.patch(url, data=data, headers=headers)
    return response.json()

@app.get("/progress/")
async def get_progress(
    conversation_id: int = Query(...),
    authorization: Optional[str] = Header(None)
):
    """
    Acts as a proxy between frontend and Django.
    Frontend calls this endpoint → FastAPI → Django → FastAPI → Frontend
    """
    
    try:
        headers = {}
        
        if authorization:
            headers["Authorization"] = authorization 

        # Forward the request to Django
        response = requests.get(
            f"{DJANGO_API_BASE}/progress/",
            params={"conversation_id": conversation_id},
            headers=headers
        )

        # Try to return Django's JSON response directly
        return JSONResponse(
            content=response.json(),
            status_code=response.status_code
        )

    except requests.exceptions.RequestException as e:
        return JSONResponse(
            content={"error": "Failed to reach Django API", "details": str(e)},
            status_code=500
        )
    except ValueError:
        # Handle case where Django returned non-JSON
        return JSONResponse(
            content={"error": "Invalid response from Django"},
            status_code=502
        )

@app.get("/progress/user/")
async def get_progress(
    authorization: Optional[str] = Header(None)
):
    """
    Acts as a proxy between frontend and Django.
    Frontend calls this endpoint → FastAPI → Django → FastAPI → Frontend
    """
    
    try:
        headers = {}
        
        if authorization:
            headers["Authorization"] = authorization 

        # Forward the request to Django
        response = requests.get(
            f"{DJANGO_API_BASE}/progress/user",
            headers=headers
        )

        # Try to return Django's JSON response directly
        return JSONResponse(
            content=response.json(),
            status_code=response.status_code
        )

    except requests.exceptions.RequestException as e:
        return JSONResponse(
            content={"error": "Failed to reach Django API", "details": str(e)},
            status_code=500
        )
    except ValueError:
        # Handle case where Django returned non-JSON
        return JSONResponse(
            content={"error": "Invalid response from Django"},
            status_code=502
        )


@app.get("/dashboard", response_class=HTMLResponse)
async def dashboard(request: Request):

    """
    Renders the dashboard page with authentication token.
    Token can come from cookies or will be passed via JavaScript.
    """
    
    # Try to get token from cookie
    token = request.cookies.get("access_token")
    
    if not token:
        # If no token in cookie, redirect to login
        return RedirectResponse(url="/", status_code=302)
    
    # Optional: Verify token here
    # payload = verify_token(token)
    # if not payload:
    #     return RedirectResponse(url="/", status_code=302)
    
    # Render the dashboard template and pass the token
    return templates.TemplateResponse("dashboard.html", {
        "request": request,
        "token": token
    })

@app.get("/admin-dashboard", response_class=HTMLResponse)
async def admin_dashboard(request: Request):
    token = request.cookies.get("access_token")
    if not token:
        return RedirectResponse(url="/", status_code=302)

    return templates.TemplateResponse("admin-dashboard.html", {
        "request": request,
        "token": token
    })



async def count_token_and_store(response_data, token: str = None):
    """Calculates and returns token counts from response metadata."""
    usage_metadata = response_data.usage_metadata

    prompt = usage_metadata.prompt_token_count or 0
    candidates = usage_metadata.candidates_token_count or 0
    thoughts = usage_metadata.thoughts_token_count or 0
    total = usage_metadata.total_token_count or 0
    if token:
        try:
            print(DJANGO_API_BASE)
            requests.post(
                f"{DJANGO_API_BASE}/user/token-usage/store/",
                headers={"Authorization": f"Bearer {token}"},
                json={
                    "prompt_tokens": prompt,
                    "candidates_tokens": candidates,
                    "thoughts_tokens": thoughts,
                    "total_tokens": total
                },
                timeout=120.0
            )
            print("token count stored in django db successfully")
        except Exception as e:
            print(f"Token usage store error: {str(e)}")

    # Return counts for local logging if needed
    print(f'Total Token Used: {total}')
    return prompt, candidates, thoughts, total
    
    
# token checker funtion

class TokenUsageChecker:
    """
    A utility class to check user token usage from Django API endpoints.
    """
    
    def __init__(self, django_api_base: str = DJANGO_API_BASE):
        self.api_base = django_api_base
    
    # async def get_user_today_token_usage(self, token: str) -> Dict:
    #     """
    #     Fetch today's token usage for a user by their JWT token.
        
    #     Args:
    #         token: User's JWT authentication token
            
    #     Returns:
    #         Dict with token usage information including:
    #         - daily_tokens: Total tokens used today
    #         - prompt_tokens: Prompt tokens used
    #         - candidates_tokens: Candidate tokens used
    #         - thoughts_tokens: Thought tokens used
    #     """
    #     try:
    #         async with httpx.AsyncClient() as client:
    #             response = await client.get(
    #                 f"{self.api_base}/user/token-usage/summary/",
    #                 headers={"Authorization": f"Bearer {token}"},
    #                 timeout=120.0
    #             )
                
    #             if response.status_code == 401:
    #                 raise HTTPException(
    #                     status_code=status.HTTP_401_UNAUTHORIZED,
    #                     detail="Invalid or expired token"
    #                 )
                
    #             if response.status_code != 200:
    #                 raise HTTPException(
    #                     status_code=response.status_code,
    #                     detail=f"Failed to fetch token usage: {response.text}"
    #                 )
                
    #             data = response.json()
    #             return {
    #                 "daily_tokens": data.get("daily_tokens", 0),
    #                 "prompt_tokens": data.get("daily_prompt_tokens", 0),
    #                 "candidates_tokens": data.get("daily_candidates_tokens", 0),
    #                 "thoughts_tokens": data.get("daily_thoughts_tokens", 0)
    #             }
    
    async def get_user_today_token_usage(self, token: str) -> Dict:
        """
        Fetch today's token usage for the authenticated user.
        """
        try:
            async with httpx.AsyncClient() as client:
                # Changed endpoint to user-specific one
                response = await client.get(
                    f"{self.api_base}/user/token-usage/today/",  # ← Changed URL
                    headers={"Authorization": f"Bearer {token}"},
                    timeout=120.0
                )
                
                if response.status_code == 401:
                    
                    return f"401 invalid token : {response.text}"
                
                if response.status_code != 200:
                    return f"Failed to fetch token usage: {response.text}"
                    
                
                data = response.json()
                
                return {
                    "daily_tokens": data.get("daily_tokens", 0),
                    "prompt_tokens": data.get("prompt_tokens", 0),
                    "candidates_tokens": data.get("candidates_tokens", 0),
                    "thoughts_tokens": data.get("thoughts_tokens", 0)
                }
            
        except:
            return "error"
        # except httpx.RequestError as e:
        #     raise HTTPException(
        #         status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
        #         detail=f"Django API connection error: {str(e)}"
        #     )
    
                    
        #     except httpx.RequestError as e:
        #         raise HTTPException(
        #             status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
        #             detail=f"Django API connection error: {str(e)}"
        #         )
    
    async def check_token_limit(
        self, 
        token: str, 
        daily_limit: int = 100000
    ) -> Dict:
        """
        Check if user has exceeded their daily token limit.
        
        Args:
            token: User's JWT authentication token
            daily_limit: Maximum tokens allowed per day (default: 100,000)
            
        Returns:
            Dict with:
            - can_proceed: bool - Whether user can make more requests
            - current_usage: int - Total tokens used today
            - daily_limit: int - Maximum allowed tokens
            - remaining_tokens: int - Tokens remaining
            - usage_percentage: float - Percentage of limit used
            - message: str - Human-readable message
        """
        usage_data = await self.get_user_today_token_usage(token)
        current_usage = usage_data["daily_tokens"]
        
        remaining = max(0, daily_limit - current_usage)
        usage_percentage = (current_usage / daily_limit) * 100 if daily_limit > 0 else 0
        can_proceed = current_usage < daily_limit
        
        if can_proceed:
            message = f"Request allowed. {remaining:,} tokens remaining today."
        else:
            message = f"Daily token limit exceeded. Used {current_usage:,}/{daily_limit:,} tokens."
        
        return {
            "can_proceed": can_proceed,
            "current_usage": current_usage,
            "daily_limit": daily_limit,
            "remaining_tokens": remaining,
            "usage_percentage": round(usage_percentage, 2),
            "message": message
        }
    
    async def get_detailed_usage(self, token: str) -> Dict:
        """
        Get detailed token usage breakdown from Django API.
        
        Args:
            token: User's JWT authentication token
            
        Returns:
            Dict with detailed daily usage by date
        """
        try:
            async with httpx.AsyncClient() as client:
                response = await client.get(
                    f"{self.api_base}/user/token-usage/list/",
                    headers={"Authorization": f"Bearer {token}"},
                    timeout=120.0
                )
                
                if response.status_code != 200:
                    raise HTTPException(
                        status_code=response.status_code,
                        detail="Failed to fetch detailed usage"
                    )
                
                return response.json()
                
        except httpx.RequestError as e:
            raise HTTPException(
                status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
                detail=f"Django API connection error: {str(e)}"
            )

token_checker = TokenUsageChecker()

async def get_user_today_token_usage(token: str) -> Dict:
    """
    Fetch today's token usage for the authenticated user.
    """
    try:
        async with httpx.AsyncClient() as client:
            # Changed endpoint to user-specific one
            response = await client.get(
                f"{DJANGO_API_BASE}/user/token-usage/today/",  # ← Changed URL
                headers={"Authorization": f"Bearer {token}"},
                timeout=120.0
            )
            
            if response.status_code == 401:
                
                return f"401 invalid token : {response.text}"
            
            if response.status_code != 200:
                return f"Failed to fetch token usage: {response.text}"
                
            
            data = response.json()
            
            return {
                "daily_tokens": data.get("daily_tokens", 0),
                "prompt_tokens": data.get("prompt_tokens", 0),
                "candidates_tokens": data.get("candidates_tokens", 0),
                "thoughts_tokens": data.get("thoughts_tokens", 0)
            }
            
    except httpx.RequestError as e:
        raise HTTPException(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            detail=f"Django API connection error: {str(e)}"
        )

