import os
import re
import time
import json
import google.generativeai as genai
import base64
import io
import uuid
import httpx
#from google import genai
from PIL import Image
from fastapi import Body
from fastapi.templating import Jinja2Templates
from fastapi import FastAPI, WebSocket, Depends, HTTPException, Form, UploadFile, File
from fastapi.responses import HTMLResponse, RedirectResponse
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 fastapi import Form, status

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
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 fastapi import Request
from index_page import home_page
from google.generativeai.types import content_types

# auth implementation imports
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from routers import auth
from schemas.user import UserBase
from utils.jwt import verify_token

app = FastAPI(title="Interactive Learning App")
load_dotenv()
app.mount("/static", StaticFiles(directory="static"), name="static")

origins = ["*"]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
app.include_router(auth.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')
sessions = {}


# Login
@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:
            # Token is valid → already logged in
            return RedirectResponse(url="/home", status_code=302)
    
    return templates.TemplateResponse("login.html", {"request": request})


@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,
    })
    
# Chat endpoint
@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)
    
):
    
    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)
    token = request.cookies.get("access_token")
    
    
    # --- Session ---
    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,
            "user_id": None,
            "first_response": None,
            "continution": None,
            "reset": None,
        }
    # --- Update session with user ID ---
    session = sessions[client_id]
    
    if session["interaction_count"] > 0 and session["interaction_count"] % 3 == 0:
        session["continution"] = await content.read()
        session["interaction_count"] +=1

        return {
        "gemini_response": "Do you want to continue with the same content, then type #Yes else #No?",
        "message_id": None,
        "audio_base64": None,
    }


    # --- Read uploaded content ---
    file_bytes = await content.read()
    mime_type = content.content_type
    file_name = content.filename

    if not file_bytes:
        return {"message": "Gemini: error - No file content received."}

    # --- Create conversation if first message ---
    if session["is_first_message"]:
        async with httpx.AsyncClient() as client:
            conv_response = await client.post(
                f"{DJANGO_API_BASE}/create-conversation/",
                headers={"Authorization": f"Bearer {token}"}
            )
            if conv_response.status_code == 201:
                conversation = conv_response.json()
                session["conversation_id"] = conversation["id"]
                session["is_first_message"] = False
            else:
                return {"message": "Gemini: error - Failed to create conversation."}

    # --- Store user message ---
    async with httpx.AsyncClient() as client:
        if session["continution"] is not None:
                session["reset"] = file_bytes.decode("utf-8").strip().upper()
                file_bytes = session["continution"]
                session["continution"] = None
        
        if message_type in ["file", "audio"]:
            # Create an in-memory file-like object
            file_obj = io.BytesIO(file_bytes)
            file_obj.name = file_name # Set name for consistency, though not strictly required for BytesIO

            try:
                # Upload the in-memory file-like object to Gemini
                uploaded_file = genai.upload_file(
                    file_obj,
                    mime_type=mime_type,
                    display_name=f"User uploaded {file_name or 'file'}"
                )
                input_to_gemini = [uploaded_file]
            except Exception as e:
                return {"message": f"Gemini: error - File processing for Gemini failed: {str(e)}"}
            # Prepare the file for Django API
            files = {
                "file": (file_name, file_bytes, mime_type)
            }
            data = {
                "sender": "user",
                "conversation_id": str(session["conversation_id"])
            }
            msg_response = await client.post(
                f"{DJANGO_API_BASE}/create-message/",
                files=files,
                data=data,
                headers={"Authorization": f"Bearer {token}"}
            )
        else:
            text_content = file_bytes.decode("utf-8").strip()
            
            if session["reset"] == "#NO":
                session["interaction_count"] = 0
                session["is_first_message"] = True
                session["conversation_id"] = None
                session["learning_history"] = []
                session["incorrect_answers"] = 0
                session["correct_answers"] = 0
                session["first_response"] = None
                session["continution"] = None
                session["reset"] = None
                session["last_question"] = ""
                session["last_response"] = ""
                session["last_interaction_time"] = None
                session["user_id"] = None
                main_content = ""
                return {
                "gemini_response": "let's start over. Please provide the content again.",
                "message_id": None,
                "audio_base64": None,
            }
    

                  
            else:
                if session:
                    main_content = session["first_response"]



            input_to_gemini = [text_content]
            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}"}
            )

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

    # --- 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", ""),
            language=language
        )

    response = g_model.generate_content(prompt)
    gemini_response = response.text
    if session["interaction_count"] == 0:
        session["first_response"] = gemini_response
        main_content = session["first_response"]

    # --- Store Gemini bot response ---
    async with httpx.AsyncClient() as client:
        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}"}
        )
        message_id = bot_msg_response.json()['id']
        if bot_msg_response.status_code not in [200, 201]:
            
            return {"message": "Gemini: error - Failed to store Gemini reply."}

    # --- Update session state ---
    session["last_question"] = extract_last_question(gemini_response)
    session["last_response"] = gemini_response
    session["interaction_count"] += 1
    session["last_interaction_time"] = time.time()

    if is_answer_correct(gemini_response):
        session["correct_answers"] += 1
    else:
        session["incorrect_answers"] += 1

    # --- TTS output ---
    audio_data = await generate_tts_audio(gemini_response, lang=language)
    audio_base64 = base64.b64encode(audio_data).decode('utf-8') if audio_data else None

    return {
        "gemini_response": gemini_response,
        "message_id": message_id,
        "audio_base64": audio_base64
    }

@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

@app.post("/api/feedback/")
async def save_feedback(request: Request,
    payload: FeedbackPayload,
    current_user_payload: dict = Depends(auth.get_current_user)
):
    token = request.cookies.get("access_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")
    
    return {"status": "ok"}