import sys
import os

if __package__ is None or __package__ == "":
    # Running as __main__ (e.g. python web/app.py)
    sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
    from utils.sql_commands import DatabaseManager
else:
    # Imported as a module (e.g. from bot.py)
    from utils.sql_commands import DatabaseManager

import os
import requests
from flask import Flask, redirect, url_for, session, request, render_template, flash
from dotenv import load_dotenv
from collections import defaultdict
import datetime
import json

load_dotenv()

app = Flask(__name__)
app.secret_key = os.getenv("SECRET_KEY")
db = DatabaseManager()

# Ensure required environment variables are loaded
DISCORD_CLIENT_ID = os.getenv("DISCORD_CLIENT_ID")
DISCORD_CLIENT_SECRET = os.getenv("DISCORD_CLIENT_SECRET")
DISCORD_REDIRECT_URI = os.getenv("DISCORD_REDIRECT_URI")
DISCORD_API_BASE_URL = "https://discord.com/api"
DISCORD_BOT_TOKEN = os.getenv("TOKEN")

# Check for missing environment variables
if not all([DISCORD_CLIENT_ID, DISCORD_CLIENT_SECRET, DISCORD_REDIRECT_URI]):
    raise EnvironmentError("One or more required environment variables are missing.")


# OAuth2 login route
@app.route("/login")
def login():
    discord_auth_url = (
        f"{DISCORD_API_BASE_URL}/oauth2/authorize"
        f"?client_id={DISCORD_CLIENT_ID}&redirect_uri={DISCORD_REDIRECT_URI}"
        f"&response_type=code&scope=identify%20guilds%20applications.commands%20bot"
    )
    return redirect(discord_auth_url)


def can_add_bot(guild):
    # Check if the user has permission to manage the bot
    permissions = guild.get(
        "permissions", 0
    )  # Ensure permissions are included in the guild data
    # Bitwise operation for managing server (assuming manage_server is 0x20)
    return (permissions & 0x20) != 0


# OAuth2 callback route
@app.route("/callback")
def callback():
    code = request.args.get("code")
    if not code:
        flash("Authorization code was not provided.")
        return redirect(url_for("home"))

    data = {
        "client_id": DISCORD_CLIENT_ID,
        "client_secret": DISCORD_CLIENT_SECRET,
        "grant_type": "authorization_code",
        "code": code,
        "redirect_uri": DISCORD_REDIRECT_URI,
    }
    headers = {"Content-Type": "application/x-www-form-urlencoded"}
    response = requests.post(
        f"{DISCORD_API_BASE_URL}/oauth2/token", data=data, headers=headers
    )

    if response.status_code != 200:
        flash("Failed to retrieve access token from Discord.")
        return redirect(url_for("home"))

    access_token = response.json().get("access_token")
    if not access_token:
        flash("Access token missing in the response.")
        return redirect(url_for("home"))

    # Store access token in session for later use
    session["access_token"] = access_token

    # Fetch user info
    user_data = requests.get(
        f"{DISCORD_API_BASE_URL}/users/@me",
        headers={"Authorization": f"Bearer {access_token}"},
    ).json()

    # Store user information in session
    session["user"] = user_data

    # Fetch guilds the user is in
    guilds_response = requests.get(
        f"{DISCORD_API_BASE_URL}/users/@me/guilds",
        headers={"Authorization": f"Bearer {access_token}"},
    )

    if guilds_response.status_code == 200:
        guilds = guilds_response.json()  # Store guilds in a variable
        session["guilds"] = guilds  # Store guilds in session

        # Fetch member count and permissions for each guild
        for guild in guilds:
            guild_id = guild["id"]
            guild_info_response = requests.get(
                f"{DISCORD_API_BASE_URL}/guilds/{guild_id}",
                headers={"Authorization": f"Bearer {access_token}"},
            )
            if guild_info_response.status_code == 200:
                guild_info = guild_info_response.json()
                guild["approx_member_count"] = guild_info.get("member_count", "N/A")
                guild["permissions"] = guild_info.get(
                    "permissions", 0
                )  # Store permissions
            else:
                guild["approx_member_count"] = "N/A"  # Fallback if unable to fetch

        # Filter guilds where user can add bots
        guilds_with_bot_permission = [guild for guild in guilds if can_add_bot(guild)]
        session["guilds_with_bot_permission"] = guilds_with_bot_permission
    else:
        flash("Failed to retrieve guilds from Discord.")

    return redirect(url_for("home"))


# Logout route
@app.route("/logout")
def logout():
    session.pop("user", None)
    session.pop("guilds", None)
    session.pop("access_token", None)  # Ensure access token is also cleared
    session.pop("guilds_with_bot_permission", None)
    flash("You have been logged out.")
    return redirect(url_for("home"))


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


# Update home route to display user info
@app.route("/")
def home():
    user = session.get("user")
    if not user:
        return redirect(
            url_for("main_page")
        )  # Redirect to the main page if not logged in

    guilds_with_permission = session.get("guilds_with_bot_permission", [])
    user_info = {
        "id": user.get("id", "N/A"),
        "username": user.get("username", "Unknown"),
        "discriminator": user.get("discriminator", "0000"),
        "avatar": user.get("avatar", None),
        "servers": len(guilds_with_permission),
    }

    return render_template(
        "home.html", user=user_info, stats=user_info, guilds=guilds_with_permission
    )


def get_user_balance(user_id):
    result = db.fetch_one("SELECT BANK, WALLET FROM economy WHERE ID = %s", (user_id,))
    print(result)
    bank_balance = result.get("BANK", 0) if result else 0
    wallet_balance = result.get("WALLET", 0) if result else 0

    return {
        "bank": bank_balance,
        "wallet": wallet_balance,
    }


@app.route("/wallet")
def wallet():
    user = session.get("user")
    if not user:
        flash("You are not logged in.")
        return redirect(url_for("login"))

    user_balance = get_user_balance(user["id"])

    return render_template("wallet.html", user=user, balance=user_balance)


def get_user_transactions(user_id, sort_by="date", order="asc"):
    valid_sort_fields = {
        "date": "TIME",
        "amount": "amount",
    }

    sort_column = valid_sort_fields.get(sort_by, "TIME")
    sort_order = "ASC" if order == "asc" else "DESC"

    query = f"SELECT * FROM transactions WHERE USERID = %s ORDER BY {sort_column} {sort_order}"
    transactions = db.fetch_all(query, (user_id,))
    return transactions if transactions else []


@app.route("/transactions")
def transactions():
    user = session.get("user")
    if not user:
        flash("You are not logged in.")
        return redirect(url_for("login"))

    sort_by = request.args.get("sort", "date")
    order = request.args.get("order", "asc")

    user_transactions = get_user_transactions(str(user["id"]), sort_by, order)
    daily_totals = defaultdict(float)

    for transaction in user_transactions:
        time_value = transaction["TIME"]
        if isinstance(time_value, str):
            try:
                time_value = datetime.datetime.fromisoformat(time_value)
            except Exception:
                try:
                    time_value = datetime.datetime.strptime(
                        time_value, "%Y-%m-%d %H:%M:%S"
                    )
                except Exception:
                    continue  # skip if can't parse
        date = time_value.date()
        amount = transaction["amount"]
        daily_totals[date] += float(amount)

    dates = list(daily_totals.keys())
    totals = list(daily_totals.values())

    return render_template(
        "transactions.html",
        user=user,
        transactions=user_transactions,
        dates=dates,
        totals=totals,
        sort_by=sort_by,
        order=order,
    )


@app.route("/add_command", methods=["GET", "POST"])
def add_command():
    user = session.get("user")
    if not user:
        flash("You are not logged in.")
        return redirect(url_for("login"))

    if request.method == "POST":
        guild_id = request.form.get("guild_id")
        command_name = request.form.get("command_name")
        response_text = request.form.get("response")

        # Save command to the database
        db.execute_query(
            "INSERT INTO custom_commands (GUILDID, COMMANDNAME, RESPONSE) VALUES (%s, %s, %s)",
            (guild_id, command_name, response_text),
        )
        flash("Custom command created successfully!")
        return redirect(url_for("home"))

    return render_template("add_command.html")


@app.route("/commands")
def list_commands():
    user = session.get("user")
    if not user:
        flash("You are not logged in.")
        return redirect(url_for("login"))

    guild_id = request.args.get("guild_id")
    commands = []
    if guild_id:
        commands = db.fetch_all(
            "SELECT * FROM custom_commands WHERE GUILDID = %s", (guild_id,)
        )
    return render_template("list_commands.html", commands=commands)


@app.route("/delete_command/<int:command_id>", methods=["POST"])
def delete_command(command_id):
    user = session.get("user")
    if not user:
        flash("You are not logged in.")
        return redirect(url_for("login"))

    db.execute_query("DELETE FROM custom_commands WHERE ID = %s", (command_id,))
    flash("Custom command deleted successfully!")
    return redirect(url_for("list_commands"))


@app.route("/guild/<guild_id>/settings", methods=["GET", "POST"])
def guild_settings(guild_id):
    user = session.get("user")
    if not user:
        flash("You are not logged in.")
        return redirect(url_for("login"))

    bot_headers = {"Authorization": f"Bot {DISCORD_BOT_TOKEN}"}
    guild_info_response = requests.get(
        f"{DISCORD_API_BASE_URL}/guilds/{guild_id}?with_counts=true",
        headers=bot_headers,
    )

    if guild_info_response.status_code != 200:
        flash("Failed to retrieve guild information (bot may not be in this guild).")
        return redirect(url_for("home"))

    guild_info = guild_info_response.json()
    owner_id = guild_info.get("owner_id", "N/A")
    member_count = guild_info.get("approximate_member_count", "N/A")

    # Fetch owner's username using the bot token
    owner_name = "Unknown"
    if owner_id != "N/A":
        owner_response = requests.get(
            f"{DISCORD_API_BASE_URL}/users/{owner_id}",
            headers=bot_headers,
        )
        if owner_response.status_code == 200:
            owner_data = owner_response.json()
            owner_name = f"{owner_data.get('username', 'Unknown')}#{owner_data.get('discriminator', '0000')}"
        else:
            owner_name = owner_id  # fallback to ID if fetch fails
    json_formatted_str = json.dumps(guild_info, indent=2)

    print(json_formatted_str)

    return render_template(
        "guild_settings.html",
        user=user,
        guild=guild_info,
        owner_name=owner_name,
        member_count=member_count,
    )


@app.route("/profile")
def profile():
    user = session.get("user")
    if not user:
        flash("Please log in to view your profile.")
        return redirect(url_for("login"))
    # Example: Fetch more user data if needed
    # user_data = db.fetch_one("SELECT ... FROM ... WHERE ID = %s", (user["id"],))
    return render_template("profile.html", user=user)


if __name__ == "__main__":
    app.run(debug=True, port=5000, host="0.0.0.0")
