from typing import Optional

import requests
from fastapi import APIRouter, Body
from fastapi import HTTPException, Depends, Query
from fastapi_sqlalchemy import db
from superagi.config.config import get_config
from superagi.helper.auth import get_user_organisation
from superagi.helper.tool_helper import get_readme_content_from_code_link, download_tool, process_files, \
    add_tool_to_json
from superagi.helper.github_helper import GithubHelper
from superagi.models.organisation import Organisation
from superagi.models.tool import Tool
from superagi.models.tool_config import ToolConfig
from superagi.models.toolkit import Toolkit
from superagi.types.common import GitHubLinkRequest
from superagi.helper.tool_helper import compare_toolkit
from superagi.helper.encyption_helper import decrypt_data, is_encrypted

router = APIRouter()


# marketplace_url = "https://app.superagi.com/api"
# marketplace_url = "http://localhost:8001/"


# For internal use
@router.get("/marketplace/list/{page}")
def get_marketplace_toolkits(
        page: int = 0,
):
    """
    Get marketplace tool kits.

    Args:
        page (int): The page number for pagination.

    Returns:
        list: A list of tool kits in the marketplace.

    """

    organisation_id = int(get_config("MARKETPLACE_ORGANISATION_ID"))
    page_size = 30

    # Apply search filter if provided
    query = db.session.query(Toolkit).filter(Toolkit.organisation_id == organisation_id)

    # Paginate the results
    toolkits = query.offset(page * page_size).limit(page_size).all()

    # Fetch tools for each tool kit
    for toolkit in toolkits:
        toolkit.tools = db.session.query(Tool).filter(Tool.toolkit_id == toolkit.id).all()
        toolkit.updated_at = toolkit.updated_at.strftime('%d-%b-%Y').upper()
    return toolkits


# For internal use
@router.get("/marketplace/details/{toolkit_name}")
def get_marketplace_toolkit_detail(toolkit_name: str):
    """
    Get tool kit details from the marketplace.

    Args:
        toolkit_name (str): The name of the tool kit.

    Returns:
        Toolkit: The tool kit details from the marketplace.

    """

    organisation_id = int(get_config("MARKETPLACE_ORGANISATION_ID"))
    toolkit = db.session.query(Toolkit).filter(Toolkit.organisation_id == organisation_id,
                                               Toolkit.name == toolkit_name).first()
    toolkit.tools = db.session.query(Tool).filter(Tool.toolkit_id == toolkit.id).all()
    toolkit.configs = db.session.query(ToolConfig).filter(ToolConfig.toolkit_id == toolkit.id).all()
    for tool_configs in toolkit.configs:
        if is_encrypted(tool_configs.value):
            tool_configs.value = decrypt_data(tool_configs.value)
    return toolkit


# For internal use
@router.get("/marketplace/readme/{toolkit_name}")
def get_marketplace_toolkit_readme(toolkit_name: str):
    """
    Get tool kit readme from the marketplace.

    Args:
        toolkit_name (str): The name of the tool kit.

    Returns:
        str: The content of the tool kit's readme file.

    Raises:
        HTTPException (status_code=404): If the specified tool kit is not found.

    """

    organisation_id = int(get_config("MARKETPLACE_ORGANISATION_ID"))
    toolkit = db.session.query(Toolkit).filter(Toolkit.name == toolkit_name,
                                               Toolkit.organisation_id == organisation_id).first()
    if not toolkit:
        raise HTTPException(status_code=404, detail='ToolKit not found')
    return get_readme_content_from_code_link(toolkit.tool_code_link)


# For internal use
@router.get("/marketplace/tools/{toolkit_name}")
def get_marketplace_toolkit_tools(toolkit_name: str):
    """
    Get tools of a specific tool kit from the marketplace.

    Args:
        toolkit_name (str): The name of the tool kit.

    Returns:
        Tool: The tools associated with the tool kit.

    Raises:
        HTTPException (status_code=404): If the specified tool kit is not found.

    """

    organisation_id = int(get_config("MARKETPLACE_ORGANISATION_ID"))
    toolkit = db.session.query(Toolkit).filter(Toolkit.name == toolkit_name,
                                               Toolkit.organisation_id == organisation_id).first()
    if not toolkit:
        raise HTTPException(status_code=404, detail="ToolKit not found")
    tools = db.session.query(Tool).filter(Tool.toolkit_id == toolkit.id).first()
    return tools


@router.get("/get/install/{toolkit_name}")
def install_toolkit_from_marketplace(toolkit_name: str,
                                     organisation: Organisation = Depends(get_user_organisation)):
    """
    Download and install a tool kit from the marketplace.

    Args:
        toolkit_name (str): The name of the tool kit.
        organisation (Organisation): The user's organisation.

    Returns:
        dict: A message indicating the successful installation of the tool kit.

    """
    # Check if the tool kit exists
    toolkit = Toolkit.fetch_marketplace_detail(search_str="details",
                                               toolkit_name=toolkit_name)
    db_toolkit = Toolkit.add_or_update(session=db.session, name=toolkit['name'], description=toolkit['description'],
                                       tool_code_link=toolkit['tool_code_link'], organisation_id=organisation.id,
                                       show_toolkit=toolkit['show_toolkit'])
    for tool in toolkit['tools']:
        Tool.add_or_update(session=db.session, tool_name=tool['name'], description=tool['description'],
                           folder_name=tool['folder_name'], class_name=tool['class_name'], file_name=tool['file_name'],
                           toolkit_id=db_toolkit.id)
    for config in toolkit['configs']:
        ToolConfig.add_or_update(session=db.session, toolkit_id=db_toolkit.id, key=config['key'], value=config['value'], key_type = config['key_type'], is_secret = config['is_secret'], is_required = config['is_required'])    
    
    return {"message": "ToolKit installed successfully"}


@router.get("/get/toolkit_name/{toolkit_name}")
def get_installed_toolkit_details(toolkit_name: str,
                                  organisation: Organisation = Depends(get_user_organisation)):
    """
    Get details of a locally installed tool kit by its name, including the details of its tools.

    Args:
        toolkit_name (str): The name of the tool kit.
        organisation (Organisation): The user's organisation.

    Returns:
        Toolkit: The tool kit object with its associated tools.

    Raises:
        HTTPException (status_code=404): If the specified tool kit is not found.

    """

    # Fetch the tool kit by its ID
    toolkit = db.session.query(Toolkit).filter(Toolkit.name == toolkit_name,
                                               Organisation.id == organisation.id).first()

    if not toolkit:
        # Return an appropriate response if the tool kit doesn't exist
        raise HTTPException(status_code=404, detail='ToolKit not found')

    # Fetch the tools associated with the tool kit
    tools = db.session.query(Tool).filter(Tool.toolkit_id == toolkit.id).all()
    # Add the tools to the tool kit object
    toolkit.tools = tools
    # readme_content = get_readme(toolkit.tool_code_link)
    return toolkit


@router.post("/get/local/install", status_code=200)
def download_and_install_tool(github_link_request: GitHubLinkRequest = Body(...),
                              organisation: Organisation = Depends(get_user_organisation)):
    """
    Install a tool locally from a GitHub link.

    Args:
        github_link_request (GitHubLinkRequest): The GitHub link request object.
        organisation (Organisation): The user's organisation.

    Returns:
        None

    Raises:
        HTTPException (status_code=400): If the GitHub link is invalid.

    """
    github_link = github_link_request.github_link
    if not GithubHelper.validate_github_link(github_link):
        raise HTTPException(status_code=400, detail="Invalid Github link")
    # download_folder = get_config("TOOLS_DIR")
    # download_tool(github_link, download_folder)
    # process_files(download_folder, db.session, organisation, code_link=github_link)
    add_tool_to_json(github_link)


@router.get("/get/readme/{toolkit_name}")
def get_installed_toolkit_readme(toolkit_name: str, organisation: Organisation = Depends(get_user_organisation)):
    """
    Get the readme content of a toolkit.

    Args:
        toolkit_name (str): The name of the toolkit.
        organisation (Organisation): The user's organisation.

    Returns:
        str: The readme content of the toolkit.

    Raises:
        HTTPException (status_code=404): If the toolkit is not found.

    """

    toolkit = db.session.query(Toolkit).filter(Toolkit.name == toolkit_name,
                                               Organisation.id == organisation.id).first()
    if not toolkit:
        raise HTTPException(status_code=404, detail='ToolKit not found')
    readme_content = get_readme_content_from_code_link(toolkit.tool_code_link)
    return readme_content


# Following APIs will be used to get marketplace related information
@router.get("/get")
def handle_marketplace_operations(
        search_str: str = Query(None, title="Search String"),
        toolkit_name: str = Query(None, title="Tool Kit Name")
):
    """
    Handle marketplace operations.

    Args:
        search_str (str, optional): The search string to filter toolkits. Defaults to None.
        toolkit_name (str, optional): The name of the toolkit. Defaults to None.

    Returns:
        dict: The response containing the marketplace details.

    """
    response = Toolkit.fetch_marketplace_detail(search_str, toolkit_name)
    return response


@router.get("/get/list")
def handle_marketplace_operations_list(
        page: int = Query(None, title="Page Number"),
        organisation: Organisation = Depends(get_user_organisation)
):
    """
    Handle marketplace operation list.

    Args:
        page (int, optional): The page number for pagination. Defaults to None.

    Returns:
        dict: The response containing the marketplace list.

    """

    marketplace_toolkits = Toolkit.fetch_marketplace_list(page=page)
    marketplace_toolkits_with_install = Toolkit.get_toolkit_installed_details(db.session, marketplace_toolkits,
                                                                              organisation)
    return marketplace_toolkits_with_install


@router.get("/get/local/list")
def get_installed_toolkit_list(organisation: Organisation = Depends(get_user_organisation)):
    """
    Get the list of installed tool kits.

    Args:
        organisation (Organisation): The organisation associated with the tool kits.

    Returns:
        list: The list of installed tool kits.

    """

    toolkits = db.session.query(Toolkit).filter(Toolkit.organisation_id == organisation.id).all()
    for toolkit in toolkits:
        toolkit_tools = db.session.query(Tool).filter(Tool.toolkit_id == toolkit.id).all()
        toolkit.tools = toolkit_tools

    return toolkits


@router.get("/check_update/{toolkit_name}")
def check_toolkit_update(toolkit_name: str, organisation: Organisation = Depends(get_user_organisation)):
    """
    Check if there is an update available for the installed tool kits.

    Returns:
        dict: The response containing the update details.

    """
    marketplace_toolkit = Toolkit.fetch_marketplace_detail(search_str="details",
                                                           toolkit_name=toolkit_name)
    if marketplace_toolkit is None:
        raise HTTPException(status_code=404, detail="Toolkit not found in marketplace")
    installed_toolkit = Toolkit.get_toolkit_from_name(db.session, toolkit_name, organisation)
    if installed_toolkit is None:
        return True
    installed_toolkit = installed_toolkit.to_dict()
    tools = Tool.get_toolkit_tools(db.session, installed_toolkit["id"])
    configs = ToolConfig.get_toolkit_tool_config(db.session, installed_toolkit["id"])
    installed_toolkit["configs"] = []
    installed_toolkit["tools"] = []

    for config in configs:
        installed_toolkit["configs"].append(config.to_dict())
    for tool in tools:
        installed_toolkit["tools"].append(tool.to_dict())

    return compare_toolkit(marketplace_toolkit, installed_toolkit)


@router.put("/update/{toolkit_name}")
def update_toolkit(toolkit_name: str, organisation: Organisation = Depends(get_user_organisation)):
    """
        Update the toolkit with the latest version from the marketplace.
    """
    marketplace_toolkit = Toolkit.fetch_marketplace_detail(search_str="details",
                                                           toolkit_name=toolkit_name)

    update_toolkit = Toolkit.add_or_update(
        db.session,
        name=marketplace_toolkit["name"],
        description=marketplace_toolkit["description"],
        show_toolkit=True if len(marketplace_toolkit["tools"]) > 1 else False,
        organisation_id=organisation.id,
        tool_code_link=marketplace_toolkit["tool_code_link"]
    )

    for tool in marketplace_toolkit["tools"]:
        Tool.add_or_update(db.session, tool_name=tool["name"], folder_name=tool["folder_name"],
                           class_name=tool["class_name"], file_name=tool["file_name"],
                           toolkit_id=update_toolkit.id, description=tool["description"])

    for tool_config_key in marketplace_toolkit["configs"]:
        ToolConfig.add_or_update(db.session, toolkit_id=update_toolkit.id, key=tool_config_key["key"], key_type = tool_config_key['key_type'], is_secret = tool_config_key['is_secret'], is_required = tool_config_key['is_required'])
