import os
import uuid
from fastapi import APIRouter, Depends, HTTPException, status, Request, Form
from fastapi.security import OAuth2PasswordRequestForm,HTTPBearer, HTTPAuthorizationCredentials
from fastapi.responses import JSONResponse
from sqlalchemy.orm import Session
import db_config.database as db
from db_config.models import User, Folder, ChatHistory, SharedFolder
import db_config.schemas as schemas
import db_config.auth as auth
from datetime import timedelta
from dependencies.helper import *
from dotenv import load_dotenv

router = APIRouter()
security = HTTPBearer()
load_dotenv()

DEFAULT_ALLOCATED_STORAGE = os.getenv('DEFAULT_ALLOCATED_STORAGE')
DEFAULT_FOLDER_LIMIT = os.getenv('DEFAULT_FOLDER_LIMIT')
DB_FOLDER = str(os.getenv('DB_PATH'))+"/"
UPLOAD_FOLDER = str(os.getenv('STORAGE_PATH'))+"/"
DEFAULT_FOLDER = os.getenv('DEFAULT_FOLDER')
EMAIL_REGEX = r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'

@router.post("/retrieve", response_model=schemas.UserResponse)
async def retrieveToken(email: str = Form(...), db: Session = Depends(db.get_db)):
    try:
        if not email:
            return errorResponse(
                "Email is required."
            )
        email = email.strip()
        
        if not re.match(EMAIL_REGEX, email):
            return JSONResponse(
                status_code=status.HTTP_400_BAD_REQUEST,
                content={
                    "status": status.HTTP_400_BAD_REQUEST,
                    "message": "Email: Invalid value."
                }
            )
        else:
            user = db.query(User).filter(User.email == email).first()
            if not user:
                return errorResponse(
                    "Unregistered Email Address."
                )
            subject = f"Answerous Access Token"
            mail_content = f"Dear {user.name}, <br/><p>PYour access token for Answerous API is {user.token}</p><br/>With Regards,<br/>Answerous Team<br/>e: support@contactous.com"

            await send_email(email,subject,mail_content)
            
            return JSONResponse(
                status_code=status.HTTP_200_OK,
                content={
                    "status": 200,
                    "message": "The token has been sent to your registered email address.",
                    # "token": user.token
                },
            )
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Server Error : {str(e)}")

# Register a new user
@router.post("/register", response_model=schemas.UserResponse)
async def register_user(user: schemas.UserCreate, db: Session = Depends(db.get_db)):
    try:
        name = user.name.strip() if user.name else ''
        email = user.email.strip() if user.email else ''
        org_id = user.org_id.strip() if user.org_id else '0000'
        org_name = user.org_name.strip() if user.org_name else '' 
        plan = user.plan.strip() if user.plan else ''
        welcome_email = user.welcome_email.strip() if user.welcome_email else 'Yes'
        
        if validate_string_length(name,3,50):
            return errorResponse(
                f"Name: Invalid value"
            )
        if not re.match(EMAIL_REGEX, email):
            return JSONResponse(
                status_code=status.HTTP_400_BAD_REQUEST,
                content={
                    "status": status.HTTP_400_BAD_REQUEST,
                    "message": "Email: Invalid value"
                }
            )
        
        db_user = db.query(User).filter(User.email == email).first()
        if db_user:
            return errorResponse(
                f"Email already registered. Retrieve the token or register a new email address"
            )
        random_text = generate_random_text()
        random_text = org_id + random_text
        hashed_password = User.hash_password(random_text)
        
        token =  f"{os.getenv('TOKEN_PREFIX')}-{uuid.uuid4()}"
        new_user = User(
            name=name, 
            email=email, 
            org_id = org_id if user.org_id else '0000',
            org_name = org_name if user.org_name else '',
            plan = plan,
            password_hash=hashed_password, 
            token = token,
            user_code=random_text,
            allocated_storage = DEFAULT_ALLOCATED_STORAGE,
            folder_limit = DEFAULT_FOLDER_LIMIT
        )
        db.add(new_user)
        db.commit()
        db.refresh(new_user)

        if not os.path.exists(str(DB_FOLDER)+str(random_text)):
            os.makedirs(str(DB_FOLDER)+str(random_text))

        if not os.path.exists(str(UPLOAD_FOLDER)+str(random_text)):
            os.makedirs(str(UPLOAD_FOLDER)+str(random_text))

        sanitized_name = replace_special_characters(DEFAULT_FOLDER)
        new_folder = Folder(
            name=DEFAULT_FOLDER, 
            parent_id=0, 
            user_id = new_user.user_id,
            shared = 'No',
            sanitized_name = sanitized_name
        )
        db.add(new_folder)
        db.commit()
        db.refresh(new_folder)

        if welcome_email == 'Yes':
            subject = f"Your Answerous API Access Token"
            mail_content = f"Dear {new_user.name},<br/><p>Thank you for signing up with Answerous. It is a RAG-as-a-service designed with the objective of giving you a simple set of flexible APIs with high quality output. The APIs can be tested within minutes and the documentation will help you to integrate them in your environment easily.</p><p>All users of Answerous have a unique access API token.</p><p>Please take note of your token. It is: {new_user.token}</p><p>Please do not hesitate to contact us if you need any help in using Answerous.</p><br/>Warm Regards,<br/>Answerous Team"

            await send_email(email,subject,mail_content)
        
        return successReponse(
            "User successfully created with this email address. Please take note of the token",
            schemas.UserResponse.from_orm(new_user).dict()
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Failed to save file: {str(e)}")

# Register a new user
@router.post("/add", response_model=schemas.UserResponse)
async def add_user(user: schemas.UserCreate, credentials: HTTPAuthorizationCredentials = Depends(security),  db: Session = Depends(db.get_db)):
    token = credentials.credentials
    org_data = auth.get_current_user(db, token)

    try:
        name = user.name.strip() if user.name else ''
        email = user.email.strip() if user.email else ''
        org_id = user.org_id.strip() if user.org_id else ''
        
        plan = user.plan.strip() if user.plan else ''
        welcome_email = user.welcome_email.strip() if user.welcome_email else 'Yes'
        
        if not org_id:
            return errorResponse(
                f"Organization ID is required"
            )
        else:
            user_org = db.query(User).filter(User.org_id == org_id).first()
        print(user_org.org_id)
        print(org_data.org_id)
        if not user_org:
            return errorResponse(
                f"Organization ID does not exist"
            )
        elif user_org.org_id != org_data.org_id:
            return errorResponse(
                f"Organization ID does not match with the organization ID"
            )
        else:
            org_name = org_data.org_name

        if validate_string_length(name,3,50):
            return errorResponse(
                f"Name: Invalid value"
            )
        if not re.match(EMAIL_REGEX, email):
            return JSONResponse(
                status_code=status.HTTP_400_BAD_REQUEST,
                content={
                    "status": status.HTTP_400_BAD_REQUEST,
                    "message": "Email: Invalid value"
                }
            )
        
        db_user = db.query(User).filter(User.email == email).first()
        if db_user:
            return errorResponse(
                f"Email already registered."
            )
        random_text = generate_random_text()
        hashed_password = User.hash_password(random_text)
        
        token =  f"{os.getenv('TOKEN_PREFIX')}-{uuid.uuid4()}"
        new_user = User(
            name=name, 
            email=email, 
            org_id = org_id if user.org_id else '0000',
            org_name = org_name if user.org_name else '',
            plan = plan,
            password_hash=hashed_password, 
            token = token,
            user_code=org_data.user_code,
            allocated_storage = DEFAULT_ALLOCATED_STORAGE,
            folder_limit = DEFAULT_FOLDER_LIMIT
        )
        db.add(new_user)
        db.commit()
        db.refresh(new_user)

        # if not os.path.exists(str(DB_FOLDER)+str(random_text)):
        #     os.makedirs(str(DB_FOLDER)+str(random_text))

        # if not os.path.exists(str(UPLOAD_FOLDER)+str(random_text)):
        #     os.makedirs(str(UPLOAD_FOLDER)+str(random_text))

        # sanitized_name = replace_special_characters(DEFAULT_FOLDER)
        # new_folder = Folder(
        #     name=DEFAULT_FOLDER, 
        #     parent_id=0, 
        #     user_id = new_user.user_id,
        #     shared = 'No',
        #     sanitized_name = sanitized_name
        # )
        # db.add(new_folder)
        # db.commit()
        # db.refresh(new_folder)
        
        # if welcome_email == 'Yes':
        #     subject = f"Your Answerous API Access Token"
        #     mail_content = f"Dear {new_user.name},<br/><p>Thank you for signing up with Answerous. It is a RAG-as-a-service designed with the objective of giving you a simple set of flexible APIs with high quality output. The APIs can be tested within minutes and the documentation will help you to integrate them in your environment easily.</p><p>All users of Answerous have a unique access API token.</p><p>Please take note of your token. It is: {new_user.token}</p><p>Please do not hesitate to contact us if you need any help in using Answerous.</p><br/>Warm Regards,<br/>Answerous Team"

        #     await send_email(email,subject,mail_content)
        
        return successReponse(
            "User successfully created with this email address.",
            schemas.OrgUserResponse.from_orm(new_user).dict()
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Failed to save file: {str(e)}")

@router.get("/detail")
async def user_detail(credentials: HTTPAuthorizationCredentials = Depends(security),  db: Session = Depends(db.get_db)):
    token = credentials.credentials
    user_data = auth.get_current_user(db, token)

    return successReponse(
            "User details retrived.",
            schemas.UserResponse.from_orm(user_data).dict()
        )

@router.get('/list')
async def list_users(credentials: HTTPAuthorizationCredentials = Depends(security), db: Session = Depends(db.get_db)):
    token = credentials.credentials
    user_data = auth.get_current_user(db, token)
    try:
        if user_data.org_id:
            users = db.query(User).filter(User.org_id == user_data.org_id).filter(User.user_id != user_data.user_id).all()
            user_data = [schemas.OrgUserResponse.from_orm(users) for users in users]
            return successReponse(
                "Users retrieved successfully",
                [user.dict() for user in user_data]
            )
        else:
            return errorResponse(
                f"This account is not organization account."
            )
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Something went wrong: {str(e)}")

@router.delete('/remove/{user_email}')
async def remove_user(user_email: str, credentials: HTTPAuthorizationCredentials = Depends(security), db: Session = Depends(db.get_db)):
    token = credentials.credentials
    user_data = auth.get_current_user(db, token)
    try:
        if not user_email:
            return errorResponse(
                "Email is required."
            )
        email = user_email.strip()
        user = db.query(User).filter(User.email == email).first()
        if not user:
            return errorResponse(
                "User does not exist."
            )
        if user.org_id != user_data.org_id:
            return errorResponse(
                "User does not belong to your organization."
            )
        db.delete(user)
        db.commit()
        return JSONResponse(
            status_code=status.HTTP_200_OK,
            content={
                "status": status.HTTP_200_OK,
                "message": "User removed successfully."
            }
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Something went wrong: {str(e)}")


@router.post('/share')
async def share_folder(share_folder: schemas.SharedFolder, credentials: HTTPAuthorizationCredentials = Depends(security), db: Session = Depends(db.get_db)):
    
    token = credentials.credentials
    user = auth.get_current_user(db, token)
    
    try:
        if not share_folder.folder_id:
            return errorResponse(
                "Folder is required."
            )
        folder_exist = db.query(Folder).filter(Folder.folder_id == share_folder.folder_id).filter(Folder.user_id == user.user_id).first()
        if not folder_exist: 
            return errorResponse(
                "Folder ID does not exist."
            )
        if not share_folder.email:
            return errorResponse(
                "Email is required."
            )
        email = share_folder.email.strip()
        organization = share_folder.organization.strip()
        access_type = share_folder.access.strip() if share_folder.access else 'Give'
        
        if not re.match(EMAIL_REGEX, email):
            return JSONResponse(
                status_code=status.HTTP_400_BAD_REQUEST,
                content={
                    "status": status.HTTP_400_BAD_REQUEST,
                    "message": "Email: Invalid value."
                }
            )
        if access_type == 'Give':
            is_exist = db.query(SharedFolder).filter(SharedFolder.folder_id == share_folder.folder_id).filter(SharedFolder.email == email).first()
            if is_exist:
                return errorResponse(
                    "The folder is already shared with the email address."
                )
                
            shared = SharedFolder(
                email=email, 
                folder_id=share_folder.folder_id,
                organization = organization if organization else ''
            )
            db.add(shared)
            db.commit()
            db.refresh(shared)
            return successReponse(
                "The folder is now shared with the email address.",
                schemas.SharedFolderResponse.from_orm(shared).dict()
            )
        elif access_type == 'Remove':
            shared_folder = db.query(SharedFolder).filter(SharedFolder.folder_id == share_folder.folder_id).filter(SharedFolder.email == email).first()
            if shared_folder:
                db.delete(shared_folder)
                db.commit()
                return JSONResponse(
                    status_code=status.HTTP_200_OK,
                    content={
                        "status": status.HTTP_200_OK,
                        "message": "The folder is no longer shareable with the email address."
                    }
                )
            else:
                return JSONResponse(
                    status_code=status.HTTP_200_OK,
                    content={
                        "status": status.HTTP_200_OK,
                        "message": "The folder is no longer shareable with the email address."
                    }
                )
        else:
            return errorResponse(
                    "Invalid access value. The value must be 'Give' or 'Remove'."
                )
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Something went wrong: {str(e)}")

@router.post("/history")
async def chat_history(
    doc_id: str = Form(...), 
    email: str = Form(...), 
    credentials: HTTPAuthorizationCredentials = Depends(security), 
    db: Session = Depends(db.get_db)
):
    
    token = credentials.credentials
    user = auth.get_current_user(db, token)
    email = email.strip() if email else ''
    try:
        if not doc_id:
            return errorResponse(
                "Please select document request."
            )
        if not email:
            return errorResponse(
                "Email is required."
            )
        
        chat_user = db.query(User).filter(User.email == email).filter(User.org_id == user.org_id).first()
        
        if not chat_user:
            return errorResponse(
                "User does not exist."
            )

        chat_history = db.query(ChatHistory).filter(ChatHistory.user_id == chat_user.user_id).filter(ChatHistory.doc_id == doc_id).all()
        chat_data = [schemas.ChatHistoryResponse.from_orm(chats) for chats in chat_history]
        
        if not chat_data:
            return successReponse(
                "No any document found.",
                []
            )
        return successReponse(
            "History retrieved successfully",
            [chat.dict() for chat in chat_data]
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Something went wrong: {str(e)}")

