# Copyright (c) 2019, JINGROW
# For license information, please see license.txt
from __future__ import annotations

import json
import re
from typing import TYPE_CHECKING

import jingrow
import pyotp
from jingrow import _
from jingrow.core.pagetype.user.user import update_password
from jingrow.core.utils import find
from jingrow.exceptions import DoesNotExistError
from jingrow.query_builder.custom import GROUP_CONCAT
from jingrow.rate_limiter import rate_limit
from jingrow.utils import cint, get_url, random_string
from jingrow.utils.data import sha256_hash
from jingrow.utils.oauth import get_oauth2_authorize_url, get_oauth_keys
from jingrow.utils.password import get_decrypted_password
from jingrow.website.utils import build_response
from pypika.terms import ValueWrapper

from jcloud.api.site import protected
from jcloud.jcloud.pagetype.team.team import (
	Team,
	get_child_team_members,
	get_team_members,
)
from jcloud.utils import get_country_info, get_current_team, is_user_part_of_team
from jcloud.utils.telemetry import capture

if TYPE_CHECKING:
	from jcloud.jcloud.pagetype.account_request.account_request import AccountRequest


@jingrow.whitelist(allow_guest=True)
def signup(email, product=None, referrer=None):
	jingrow.utils.validate_email_address(email, True)

	current_user = jingrow.session.user
	jingrow.set_user("Administrator")

	email = email.strip().lower()
	exists, enabled = jingrow.db.get_value("Team", {"user": email}, ["name", "enabled"]) or [0, 0]

	account_request = None
	if exists and not enabled:
		jingrow.throw(_("Account {0} has been deactivated").format(email))
	elif exists and enabled:
		jingrow.throw(_("Account {0} is already registered").format(email))
	else:
		account_request = jingrow.get_pg(
			{
				"pagetype": "Account Request",
				"email": email,
				"role": "Jcloud Admin",
				"referrer_id": referrer,
				"send_email": True,
				"product_trial": product,
			}
		).insert()

	jingrow.set_user(current_user)
	if account_request:
		return account_request.name
	return None

	return None

@jingrow.whitelist(allow_guest=True)
@rate_limit(limit=50, seconds=60 * 60)
def signup_with_username(username, password, email=None, phone_number=None, referrer=None, product=None):
	"""
	使用用户名注册新账户，邮箱和手机号为可选
	返回格式: {"success": bool, "message": str, "dashboard_route": str}
	"""
	from jingrow.utils import validate_email_address
	from jingrow.utils.password import update_password
	
	current_user = jingrow.session.user
	jingrow.set_user("Administrator")  # 确保有权限创建用户
	
	try:
		# 验证用户名
		if not username or len(username) < 3:
			return {
				"success": False,
				"message": "用户名至少需要3个字符"
			}
			
		# 检查用户名是否已存在
		if jingrow.db.exists("User", {"username": username}):
			return {
				"success": False,
				"message": "该用户名已被使用"
			}
		
		# 如果提供了邮箱，验证邮箱格式并检查是否已存在
		user_email = None
		if email:
			try:
				validate_email_address(email, True)
			except:
				return {
					"success": False,
					"message": "请输入有效的邮箱地址"
				}
				
			if jingrow.db.exists("User", {"email": email}):
				return {
					"success": False,
					"message": "该邮箱已被注册"
				}
			user_email = email
		
		# 如果提供了手机号，验证手机号格式并检查是否已存在
		if phone_number:
			if not re.match(r'^1[3-9]\d{9}$', phone_number):
				return {
					"success": False,
					"message": "请输入有效的手机号码"
				}
			if jingrow.db.exists("User", {"mobile_no": phone_number}):
				return {
					"success": False,
					"message": "该手机号已被注册"
				}
		
		# 创建用户，但先不设置密码
		user_pg = {
			"pagetype": "User",
			"first_name": username,
			"username": username,
			"send_welcome_email": 0,
			"user_type": "Website User",
			"language": "zh"  # 设置默认语言为中文
		}
		
		# 只有提供了邮箱时才添加到用户数据
		if user_email:
			user_pg["email"] = user_email
		
		# 如果提供了手机号，添加到用户数据
		if phone_number:
			user_pg["mobile_no"] = phone_number
		
		user = jingrow.get_pg(user_pg)
		
		# 添加角色 - 设置为 Jcloud Admin
		user.append("roles", {
			"role": "Jcloud Admin"
		})
		
		user.insert(ignore_permissions=True)
		
		# 在创建用户后显式更新密码，这样可以确保密码被正确加密和保存
		update_password(username, password)
		
		# 创建团队
		team_pg = {
			"pagetype": "Team", 
			"enabled": 1,
			"team_name": username,
			"country": "China",  # 默认设置为中国
			"payment_mode": "Prepaid Credits",  # 设置默认支付方式为余额支付
			"user": username  # 使用用户名作为团队用户标识
		}
		
		# 只有当提供有效邮箱时，才设置账单邮箱和通知邮箱
		if user_email:
			team_pg["billing_email"] = user_email
			team_pg["notify_email"] = user_email
		
		team = jingrow.get_pg(team_pg)
		
		# 添加团队成员 - 使用用户名
		team.append("team_members", {
			"user": username
		})
		
		# 如果有邮箱，添加通讯邮箱
		if user_email:
			team.append("communication_emails", {
				"type": "invoices", 
				"value": user_email
			})
			team.append("communication_emails", {
				"type": "marketplace_notifications", 
				"value": user_email
			})
		
		# 插入团队
		team.insert(ignore_permissions=True)
		
		# 登录用户
		jingrow.local.login_manager.login_as(username)
			
		jingrow.db.commit()
		
		# 返回成功响应
		return {
			"success": True,
			"message": "注册成功",
			"dashboard_route": ""
		}
		
	except Exception as e:
		# 捕获其他异常并返回错误消息
		jingrow.log_error("signup_with_username 错误", str(e))
		return {
			"success": False,
			"message": f"注册失败: {str(e)}"
		}
	finally:
		# 恢复原始用户
		jingrow.set_user(current_user)

@jingrow.whitelist(allow_guest=True)
@rate_limit(limit=5, seconds=60)
def send_otp(email: str):
	"""
	向用户发送登录验证码
	"""
	if not jingrow.db.exists("User", email):
		jingrow.throw("该邮箱尚未注册账户")

	last_otp = jingrow.cache().get_value(f"login_otp_generated_at:{email}")
	if last_otp and (jingrow.utils.now_datetime() - last_otp).seconds < 30:
		jingrow.throw("请在30秒后再请求新的验证码")

	# 生成6位数字OTP
	import random
	otp = ''.join(random.choices('0123456789', k=6))
	expires_in_seconds = 300  # 5分钟
	
	jingrow.cache().set_value(
		f"login_otp:{email}",
		otp,
		expires_in_sec=expires_in_seconds
	)
	jingrow.cache().set_value(
		f"login_otp_generated_at:{email}",
		jingrow.utils.now_datetime(),
		expires_in_sec=expires_in_seconds
	)

	if jingrow.conf.developer_mode:
		print(f"\n登录OTP给 {email}: {otp}\n")
	else:
		# 获取用户全名
		full_name = jingrow.db.get_value("User", email, "full_name") or email.split("@")[0]
		
		jingrow.sendmail(
			subject="Jingrow 登录验证码",
			recipients=email,
			template="verification_code_for_login",
			args={
				"otp": otp, 
				"minutes": expires_in_seconds // 60,
				"full_name": full_name
			},
			now=True,
		)
	
	return True


@jingrow.whitelist(allow_guest=True)
@rate_limit(limit=5, seconds=60 * 60)
def verify_otp_and_login(email: str, otp: str):
	"""
	验证OTP并登录用户
	"""
	if not jingrow.db.exists("User", email):
		jingrow.throw("该邮箱尚未注册账户")

	stored_otp = jingrow.cache().get_value(f"login_otp:{email}")
	if not stored_otp:
		jingrow.throw("验证码已过期")

	if stored_otp != otp:
		jingrow.throw("验证码无效")

	# 清除缓存
	jingrow.cache().delete_value(f"login_otp:{email}")
	jingrow.cache().delete_value(f"login_otp_generated_at:{email}")
	
	# 登录用户
	jingrow.local.login_manager.login_as(email)
	
	# 登陆重定向
	return {
		"dashboard_route": ""
	}


@jingrow.whitelist(allow_guest=True)
@rate_limit(limit=5, seconds=60 * 60)
def verify_otp(account_request: str, otp: str):
	account_request: "AccountRequest" = jingrow.get_pg("Account Request", account_request)
	# ensure no team has been created with this email
	if jingrow.db.exists("Team", {"user": account_request.email}) and not account_request.product_trial:
		jingrow.throw("Invalid OTP. Please try again.")
	if account_request.otp != otp:
		jingrow.throw("Invalid OTP. Please try again.")
	account_request.reset_otp()
	return account_request.request_key


@jingrow.whitelist(allow_guest=True)
@rate_limit(limit=5, seconds=60)
def resend_otp(account_request: str):
	account_request: "AccountRequest" = jingrow.get_pg("Account Request", account_request)

	# if last OTP was sent less than 30 seconds ago, throw an error
	if (
		account_request.otp_generated_at
		and (jingrow.utils.now_datetime() - account_request.otp_generated_at).seconds < 30
	):
		jingrow.throw("Please wait for 30 seconds before requesting a new OTP")

	# ensure no team has been created with this email
	if jingrow.db.exists("Team", {"user": account_request.email}) and not account_request.product_trial:
		jingrow.throw("Invalid Email")
	account_request.reset_otp()
	account_request.send_verification_email()


@jingrow.whitelist(allow_guest=True)
def setup_account(  # noqa: C901
	key,
	first_name=None,
	last_name=None,
	password=None,
	is_invitation=False,
	country=None,
	user_exists=False,
	accepted_user_terms=False,
	invited_by_parent_team=False,
	oauth_signup=False,
	oauth_domain=False,
):
	account_request = get_account_request_from_key(key)
	if not account_request:
		jingrow.throw("Invalid or Expired Key")

	if not user_exists:
		if not first_name:
			jingrow.throw("名字是必填项")

		if not password and not (oauth_signup or oauth_domain):
			jingrow.throw("密码是必填项")

		if not is_invitation and not country:
			jingrow.throw("国家是必填项")

		if not is_invitation and country:
			all_countries = jingrow.db.get_all("Country", pluck="name")
			country = find(all_countries, lambda x: x.lower() == country.lower())
			if not country:
				jingrow.throw("Please provide a valid country name")

	if not accepted_user_terms:
		jingrow.throw("Please accept our Terms of Service & Privacy Policy to continue")

	# if the request is authenticated, set the user to Administrator
	jingrow.set_user("Administrator")

	team = account_request.team
	email = account_request.email
	role = account_request.role
	jcloud_roles = account_request.jcloud_roles

	if is_invitation:
		# if this is a request from an invitation
		# then Team already exists and will be added to that team
		pg = jingrow.get_pg("Team", team)
		pg.create_user_for_member(first_name, last_name, email, password, role, jcloud_roles)
	else:
		# Team doesn't exist, create it
		Team.create_new(
			account_request=account_request,
			first_name=first_name,
			last_name=last_name,
			password=password,
			country=country,
			user_exists=bool(user_exists),
		)
		if invited_by_parent_team:
			pg = jingrow.get_pg("Team", account_request.invited_by)
			pg.append("child_team_members", {"child_team": team})
			pg.save()

	# Telemetry: Created account
	capture("completed_signup", "fc_signup", account_request.email)
	jingrow.local.login_manager.login_as(email)

	return account_request.name


@jingrow.whitelist(allow_guest=True)
@rate_limit(limit=5, seconds=60 * 60)
def send_login_link(email):
	if not jingrow.db.exists("User", email):
		jingrow.throw("No registered account with this email address")

	key = jingrow.generate_hash("Login Link", 20)
	minutes = 10
	jingrow.cache().set_value(f"one_time_login_key:{key}", email, expires_in_sec=minutes * 60)

	link = get_url(f"/api/action/jcloud.api.account.login_using_key?key={key}")

	if jingrow.conf.developer_mode:
		print()
		print(f"One time login link for {email}")
		print(link)
		print()

	jingrow.sendmail(
		subject="Login to Jingrow",
		recipients=email,
		template="one_time_login_link",
		args={"link": link, "minutes": minutes},
		now=True,
	)


@jingrow.whitelist(allow_guest=True)
@rate_limit(limit=5, seconds=60 * 60)
def login_using_key(key):
	cache_key = f"one_time_login_key:{key}"
	email = jingrow.cache().get_value(cache_key)

	if email:
		jingrow.cache().delete_value(cache_key)
		jingrow.local.login_manager.login_as(email)
		jingrow.response.type = "redirect"
		jingrow.response.location = "/dashboard"
	else:
		jingrow.respond_as_web_page(
			_("Not Permitted"),
			_("The link using which you are trying to login is invalid or expired."),
			http_status_code=403,
			indicator_color="red",
		)


@jingrow.whitelist()
def active_servers():
	team = get_current_team()
	return jingrow.get_all("Server", {"team": team, "status": "Active"}, ["title", "name"])


@jingrow.whitelist()
def disable_account(totp_code: str | None):
	user = jingrow.session.user
	team = get_current_team(get_pg=True)

	if is_2fa_enabled(user):
		if not totp_code:
			jingrow.throw("2FA Code is required")
		if not verify_2fa(user, totp_code):
			jingrow.throw("Invalid 2FA Code")

	if user != team.user:
		jingrow.throw("Only team owner can disable the account")

	team.disable_account()


@jingrow.whitelist()
def has_active_servers(team):
	return jingrow.db.exists("Server", {"status": "Active", "team": team})


@jingrow.whitelist()
def enable_account():
	team = get_current_team(get_pg=True)
	if jingrow.session.user != team.user:
		jingrow.throw("Only team owner can enable the account")
	team.enable_account()


@jingrow.whitelist()
def request_team_deletion():
	team = get_current_team(get_pg=True)
	pg = jingrow.get_pg({"pagetype": "Team Deletion Request", "team": team.name}).insert()
	return pg.name


@jingrow.whitelist(allow_guest=True)
def delete_team(team):
	from jingrow.utils.verified_command import verify_request

	responses = {
		"invalid": [
			("Link Invalid", "This link is invalid or expired."),
			{"indicator_color": "red"},
		],
		"confirmed": [
			(
				"Confirmed",
				f"The process for deletion of your team {team} has been initiated. Sorry to see you go :(",
			),
			{"indicator_color": "green"},
		],
		"expired": [
			("Link Expired", "This link has already been activated for verification."),
			{"indicator_color": "red"},
		],
	}

	def respond_as_web_page(key):
		jingrow.respond_as_web_page(*responses[key][0], **responses[key][1])

	if verify_request() or jingrow.flags.in_test:
		jingrow.set_user("Administrator")
	else:
		return respond_as_web_page("invalid")

	try:
		pg = jingrow.get_last_pg("Team Deletion Request", {"team": team})
	except jingrow.DoesNotExistError:
		return respond_as_web_page("invalid")

	if pg.status != "Pending Verification":
		return respond_as_web_page("expired")

	pg.status = "Deletion Verified"
	pg.save()
	jingrow.db.commit()

	return respond_as_web_page("confirmed")


@jingrow.whitelist(allow_guest=True)
def validate_request_key(key, timezone=None):
	from jcloud.utils.country_timezone import get_country_from_timezone

	account_request = get_account_request_from_key(key)
	if account_request:
		data = get_country_info()
		possible_country = data.get("country") or get_country_from_timezone(timezone)
		if not (account_request.is_saas_signup() or account_request.invited_by_parent_team):
			capture("clicked_verify_link", "fc_signup", account_request.email)
		return {
			"email": account_request.email,
			"first_name": account_request.first_name,
			"last_name": account_request.last_name,
			"country": possible_country,
			"countries": jingrow.db.get_all("Country", pluck="name"),
			"user_exists": jingrow.db.exists("User", account_request.email),
			"team": account_request.team,
			"is_invitation": jingrow.db.get_value("Team", account_request.team, "enabled"),
			"invited_by": account_request.invited_by,
			"invited_by_parent_team": account_request.invited_by_parent_team,
			"oauth_signup": account_request.oauth_signup,
			"oauth_domain": jingrow.db.exists(
				"OAuth Domain Mapping", {"email_domain": account_request.email.split("@")[1]}
			),
			"product_trial": jingrow.db.get_value(
				"Product Trial", account_request.product_trial, ["logo", "title", "name"], as_dict=1
			),
		}
	return None

	return None


@jingrow.whitelist(allow_guest=True)
def country_list():
	def get_country_list():
		return jingrow.db.get_all("Country", fields=["name", "code"])

	return jingrow.cache().get_value("country_list", generator=get_country_list)


def clear_country_list_cache():
	jingrow.cache().delete_value("country_list")


@jingrow.whitelist()
def set_country(country):
	team_pg = get_current_team(get_pg=True)
	team_pg.country = country
	team_pg.save()
	team_pg.create_stripe_customer()


def get_account_request_from_key(key):
	"""Find Account Request using `key` in the past 12 hours or if site is active"""

	if not key or not isinstance(key, str):
		jingrow.throw(_("Invalid Key"))

	hours = 12
	ar = jingrow.get_pg("Account Request", {"request_key": key})
	if ar.creation > jingrow.utils.add_to_date(None, hours=-hours):
		return ar
	if ar.subdomain and ar.saas_app:
		domain = jingrow.db.get_value("Saas Settings", ar.saas_app, "domain")
		if jingrow.db.get_value("Site", ar.subdomain + "." + domain, "status") == "Active":
			return ar
	return None

	return None


@jingrow.whitelist()
def get():
	cached = jingrow.cache.get_value("cached-account.get", user=jingrow.session.user)
	if cached:
		return cached
	value = _get()
	jingrow.cache.set_value("cached-account.get", value, user=jingrow.session.user, expires_in_sec=60)
	return value


def _get():
	user = jingrow.session.user
	if not jingrow.db.exists("User", user):
		jingrow.throw(_("Account does not exist"))

	team_pg = get_current_team(get_pg=True)

	parent_teams = [d.parent for d in jingrow.db.get_all("Team Member", {"user": user}, ["parent"])]

	teams = []
	if parent_teams:
		Team = jingrow.qb.PageType("Team")
		teams = (
			jingrow.qb.from_(Team)
			.select(Team.name, Team.team_title, Team.user)
			.where((Team.enabled == 1) & (Team.name.isin(parent_teams)))
			.run(as_dict=True)
		)

	partner_billing_name = ""
	if team_pg.partner_email:
		partner_billing_name = jingrow.db.get_value(
			"Team",
			{"jerp_partner": 1, "partner_email": team_pg.partner_email},
			"billing_name",
		)
	number_of_sites = jingrow.db.count("Site", {"team": team_pg.name, "status": ("!=", "Archived")})

	return {
		"user": jingrow.get_pg("User", user),
		"ssh_key": get_ssh_key(user),
		"team": team_pg,
		"team_members": get_team_members(team_pg.name),
		"child_team_members": get_child_team_members(team_pg.name),
		"teams": list(teams if teams else parent_teams),
		"onboarding": team_pg.get_onboarding(),
		"balance": team_pg.get_balance(),
		"parent_team": team_pg.parent_team or "",
		"saas_site_request": team_pg.get_pending_saas_site_request(),
		"feature_flags": {
			"verify_cards_with_micro_charge": jingrow.db.get_single_value(
				"Jcloud Settings", "verify_cards_with_micro_charge"
			)
		},
		"partner_email": team_pg.partner_email or "",
		"partner_billing_name": partner_billing_name,
		"number_of_sites": number_of_sites,
		"permissions": get_permissions(),
		"billing_info": team_pg.billing_info(),
	}


@jingrow.whitelist()
def current_team():
	user = jingrow.session.user
	if not jingrow.db.exists("User", user):
		jingrow.throw(_("Account does not exist"))

	from jcloud.api.client import get

	return get("Team", jingrow.local.team().name)


def get_permissions():
	user = jingrow.session.user
	groups = tuple(
		[*jingrow.get_all("Jcloud Permission Group User", {"user": user}, pluck="parent"), "1", "2"]
	)  # [1, 2] is for avoiding singleton tuples
	pageperms = jingrow.db.sql(
		f"""
			SELECT `document_name`, GROUP_CONCAT(`action`) as `actions`
			FROM `tabJcloud User Permission`
			WHERE user='{user}' or `group` in {groups}
			GROUP BY `document_name`
		""",
		as_dict=True,
	)
	return {perm.document_name: perm.actions.split(",") for perm in pageperms if perm.actions}


@jingrow.whitelist()
def has_method_permission(pagetype, docname, method) -> bool:
	from jcloud.jcloud.pagetype.jcloud_permission_group.jcloud_permission_group import (
		has_method_permission,
	)

	return has_method_permission(pagetype, docname, method)


@jingrow.whitelist(allow_guest=True)
def signup_settings(product=None, fetch_countries=False, timezone=None):
	from jcloud.utils.country_timezone import get_country_from_timezone

	settings = jingrow.get_single("Jcloud Settings")

	product = jingrow.utils.cstr(product)
	product_trial = None
	if product:
		product_trial = jingrow.db.get_value(
			"Product Trial",
			{"name": product, "published": 1},
			["title", "logo"],
			as_dict=1,
		)

	data = {
		"enable_google_oauth": settings.enable_google_oauth,
		"product_trial": product_trial,
		"oauth_domains": jingrow.get_all(
			"OAuth Domain Mapping", ["email_domain", "social_login_key", "provider_name"]
		),
	}

	if fetch_countries:
		data["countries"] = jingrow.db.get_all("Country", pluck="name")
		data["country"] = get_country_info().get("country") or get_country_from_timezone(timezone)

	return data


@jingrow.whitelist(allow_guest=True)
def guest_feature_flags():
	return {
		"enable_google_oauth": jingrow.db.get_single_value("Jcloud Settings", "enable_google_oauth"),
	}


@jingrow.whitelist()
def create_child_team(title):
	team = title.strip()

	current_team = get_current_team(True)
	if title in [
		d.team_title for d in jingrow.get_all("Team", {"parent_team": current_team.name}, ["team_title"])
	]:
		jingrow.throw(f"Child Team {title} already exists.")
	elif title == "Parent Team":
		jingrow.throw("Child team name cannot be same as parent team")

	pg = jingrow.get_pg(
		{
			"pagetype": "Team",
			"team_title": team,
			"user": current_team.user,
			"parent_team": current_team.name,
			"enabled": 1,
		}
	)
	pg.insert(ignore_permissions=True, ignore_links=True)
	pg.append("team_members", {"user": current_team.user})
	pg.save()

	current_team.append("child_team_members", {"child_team": pg.name})
	current_team.save()

	return "created"


def new_team(email, current_team):
	jingrow.utils.validate_email_address(email, True)

	jingrow.get_pg(
		{
			"pagetype": "Account Request",
			"email": email,
			"role": "Jcloud Member",
			"send_email": True,
			"team": email,
			"invited_by": current_team,
			"invited_by_parent_team": 1,
		}
	).insert()

	return "new_team"


def get_ssh_key(user):
	ssh_keys = jingrow.get_all(
		"User SSH Key", {"user": user, "is_default": True}, order_by="creation desc", limit=1
	)
	if ssh_keys:
		return jingrow.get_pg("User SSH Key", ssh_keys[0])

	return None


@jingrow.whitelist()
def update_profile(first_name=None, last_name=None, email=None, username=None, mobile_no=None):
	if email:
		# 更新用户所有相关邮箱
		update_profile_email(email)
	
	# 验证用户名（如果提供）
	if username:
		if len(username) < 3:
			jingrow.throw("用户名至少需要3个字符")
		
		# 检查用户名是否已被其他用户使用
		user = jingrow.session.user
		username_exists = jingrow.db.exists(
			"User", 
			{"username": username, "name": ("!=", user)}
		)
		if username_exists:
			jingrow.throw("该用户名已被使用")
	
	# 验证手机号（如果提供）
	if mobile_no:
		import re
		if not re.match(r'^1[3-9]\d{9}$', mobile_no):
			jingrow.throw("请输入有效的手机号码")
		
		# 检查手机号是否已被其他用户使用
		phone_exists = jingrow.db.exists(
			"User", 
			{"mobile_no": mobile_no, "name": ("!=", user)}
		)
		if phone_exists:
			jingrow.throw("该手机号已被注册")
	
	user = jingrow.session.user
	pg = jingrow.get_pg("User", user)
	pg.first_name = first_name
	pg.last_name = last_name
	
	if username:
		pg.username = username
	
	if mobile_no:
		pg.mobile_no = mobile_no
	
	pg.save(ignore_permissions=True)
	return pg


@jingrow.whitelist()
def update_profile_picture():
	user = jingrow.session.user
	_file = jingrow.get_pg(
		{
			"pagetype": "File",
			"attached_to_pagetype": "User",
			"attached_to_name": user,
			"attached_to_field": "user_image",
			"folder": "Home/Attachments",
			"file_name": jingrow.local.uploaded_filename,
			"is_private": 0,
			"content": jingrow.local.uploaded_file,
		}
	)
	_file.save(ignore_permissions=True)
	jingrow.db.set_value("User", user, "user_image", _file.file_url)


@jingrow.whitelist()
def update_feature_flags(values=None):
	jingrow.only_for("Jcloud Admin")
	team = get_current_team(get_pg=True)
	values = jingrow.parse_json(values)
	fields = [
		"benches_enabled",
		"servers_enabled",
		"self_hosted_servers_enabled",
		"security_portal_enabled",
	]
	for field in fields:
		if field in values:
			team.set(field, values[field])
	team.save()


@jingrow.whitelist(allow_guest=True)
@rate_limit(limit=5, seconds=60 * 60)
def send_reset_password_email(email: str):
	valid_email = jingrow.utils.validate_email_address(email)
	if not valid_email:
		jingrow.throw(
			f"{email} is not a valid email address",
			jingrow.InvalidEmailAddressError,
		)

	valid_email = valid_email.strip()
	key = jingrow.generate_hash()
	hashed_key = sha256_hash(key)
	if jingrow.db.exists("User", valid_email):
		jingrow.db.set_value(
			"User",
			valid_email,
			{
				"reset_password_key": hashed_key,
				"last_reset_password_key_generated_on": jingrow.utils.now_datetime(),
			},
		)
		url = get_url("/dashboard/reset-password/" + key)
		if jingrow.conf.developer_mode:
			print(f"\nReset password URL for {valid_email}:")
			print(url)
			print()
			return
		jingrow.sendmail(
			recipients=valid_email,
			subject="Reset Password",
			template="reset_password",
			args={"link": url},
			now=True,
		)
	else:
		jingrow.throw(f"User {valid_email} does not exist")


@jingrow.whitelist(allow_guest=True)
def reset_password(key, password):
	return update_password(new_password=password, key=key)


@jingrow.whitelist(allow_guest=True)
def get_user_for_reset_password_key(key):
	if not key or not isinstance(key, str):
		jingrow.throw(_("Invalid Key"))

	hashed_key = sha256_hash(key)
	return jingrow.db.get_value("User", {"reset_password_key": hashed_key}, "name")


@jingrow.whitelist()
def remove_team_member(user_email):
	team = get_current_team(True)
	team.remove_team_member(user_email)


@jingrow.whitelist()
def remove_child_team(child_team):
	team = jingrow.get_pg("Team", child_team)
	sites = jingrow.get_all("Site", {"status": ("!=", "Archived"), "team": team.name}, pluck="name")
	if sites:
		jingrow.throw("Child team has Active Sites")

	team.enabled = 0
	team.parent_team = ""
	team.save(ignore_permissions=True)


@jingrow.whitelist()
def can_switch_to_team(team):
	if not jingrow.db.exists("Team", team):
		return False
	if jingrow.local.system_user():
		return True
	if is_user_part_of_team(jingrow.session.user, team):
		return True
	return False


@jingrow.whitelist()
def switch_team(team):
	user_is_part_of_team = jingrow.db.exists("Team Member", {"parent": team, "user": jingrow.session.user})
	user_is_system_user = jingrow.session.data.user_type == "System User"
	if user_is_part_of_team or user_is_system_user:
		jingrow.db.set_value("Team", {"user": jingrow.session.user}, "last_used_team", team)
		jingrow.cache.delete_value("cached-account.get", user=jingrow.session.user)
		return {
			"team": jingrow.get_pg("Team", team),
			"team_members": get_team_members(team),
		}
	return None


@jingrow.whitelist()
def leave_team(team):
	team_to_leave = jingrow.get_pg("Team", team)
	cur_team = jingrow.session.user

	if team_to_leave.user == cur_team:
		jingrow.throw("Cannot leave this team as you are the owner.")

	team_to_leave.remove_team_member(cur_team)


@jingrow.whitelist()
def get_billing_information(timezone=None):
	from jcloud.utils.country_timezone import get_country_from_timezone

	team = get_current_team(True)

	billing_details = jingrow._dict()
	if team.billing_address:
		billing_details = jingrow.get_pg("Address", team.billing_address).as_dict()
		billing_details.billing_name = team.billing_name

	if not billing_details.country and timezone:
		billing_details.country = get_country_from_timezone(timezone)

	return billing_details


@jingrow.whitelist()
def update_billing_information(billing_details):
	billing_details = jingrow._dict(billing_details)
	team = get_current_team(get_pg=True)
	validate_pincode(billing_details)
	if (team.country != billing_details.country) and (
		team.country == "China" or billing_details.country == "China"
	):
		jingrow.throw("Cannot change country after registration")
	team.update_billing_details(billing_details)


def validate_pincode(billing_details):

	if billing_details.country != "China" or not billing_details.postal_code:
		return
	PINCODE_FORMAT = re.compile(r"^[1-9][0-9]{5}$")
	if not PINCODE_FORMAT.match(billing_details.postal_code):
		jingrow.throw("Invalid Postal Code")

	if billing_details.state not in STATE_PINCODE_MAPPING:
		return

	first_three_digits = cint(billing_details.postal_code[:3])
	postal_code_range = STATE_PINCODE_MAPPING[billing_details.state]

	if isinstance(postal_code_range[0], int):
		postal_code_range = (postal_code_range,)

	for lower_limit, upper_limit in postal_code_range:
		if lower_limit <= int(first_three_digits) <= upper_limit:
			return

	jingrow.throw(f"Postal Code {billing_details.postal_code} is not associated with {billing_details.state}")


@jingrow.whitelist(allow_guest=True)
def feedback(team, message, note, rating, route=None):
	feedback = jingrow.new_pg("Jcloud Feedback")
	team_pg = jingrow.get_pg("Team", team)
	feedback.team = team
	feedback.message = message
	feedback.note = note
	feedback.route = route
	feedback.rating = rating / 5
	feedback.team_created_on = jingrow.utils.getdate(team_pg.creation)
	feedback.currency = team_pg.currency
	invs = jingrow.get_all(
		"Invoice",
		{"team": team, "status": "Paid", "type": "Subscription"},
		pluck="total",
		order_by="creation desc",
		limit=1,
	)
	feedback.last_paid_invoice = 0 if not invs else invs[0]
	feedback.insert(ignore_permissions=True)


@jingrow.whitelist()
def get_site_count(team):
	return jingrow.db.count("Site", {"team": team, "status": ("=", "Active")})


@jingrow.whitelist()
def user_prompts():
	if jingrow.local.dev_server:
		return None

	team = get_current_team(True)
	pg = jingrow.get_pg("Team", team.name)

	onboarding = pg.get_onboarding()
	if not onboarding["complete"]:
		return None

	if not pg.billing_address:
		return [
			"UpdateBillingDetails",
			"Update your billing details so that we can show it in your monthly invoice.",
		]

	gstin, country = jingrow.db.get_value("Address", pg.billing_address, ["gstin", "country"])
	if country == "China" and not gstin:
		return [
			"UpdateBillingDetails",
			"If you have a registered GSTIN number, you are required to update it, so that we can generate a GST Invoice.",
		]
	return None


def redirect_to(location):
	return build_response(
		jingrow.local.request.path,
		"",
		301,
		{"Location": location, "Cache-Control": "no-store, no-cache, must-revalidate"},
	)


def get_jingrow_io_auth_url() -> str | None:
	"""Get auth url for oauth login with jingrow.com."""

	try:
		provider = jingrow.get_last_pg(
			"Social Login Key", filters={"enable_social_login": 1, "provider_name": "Jingrow"}
		)
	except DoesNotExistError:
		return None

	if (
		provider.base_url
		and provider.client_id
		and get_oauth_keys(provider.name)
		and provider.get_password("client_secret")
	):
		return get_oauth2_authorize_url(provider.name, redirect_to="")
	return None


@jingrow.whitelist()
def get_emails():
	team = get_current_team(get_pg=True)
	return [
		{
			"type": "billing_email",
			"value": team.billing_email,
		},
		{
			"type": "notify_email",
			"value": team.notify_email,
		},
	]


@jingrow.whitelist()
def update_emails(data):
	from jingrow.utils import validate_email_address

	data = {x["type"]: x["value"] for x in json.loads(data)}
	for _key, value in data.items():
		validate_email_address(value, throw=True)

	team_pg = get_current_team(get_pg=True)

	team_pg.billing_email = data["billing_email"]
	team_pg.notify_email = data["notify_email"]

	team_pg.save()


@jingrow.whitelist()
def add_key(key):
	jingrow.get_pg({"pagetype": "User SSH Key", "user": jingrow.session.user, "ssh_public_key": key}).insert()


@jingrow.whitelist()
def mark_key_as_default(key_name):
	key = jingrow.get_pg("User SSH Key", key_name)
	key.is_default = True
	key.save()


@jingrow.whitelist()
def create_api_secret():
	user = jingrow.get_pg("User", jingrow.session.user)

	api_key = user.api_key
	api_secret = jingrow.generate_hash()

	if not api_key:
		api_key = jingrow.generate_hash()
		user.api_key = api_key

	user.api_secret = api_secret
	user.save(ignore_permissions=True)

	return {"api_key": api_key, "api_secret": api_secret}


@jingrow.whitelist()
def me():
	return {"user": jingrow.session.user, "team": get_current_team()}


@jingrow.whitelist()
def fuse_list():
	team = get_current_team(get_pg=True)
	query = f"""
		SELECT
			'Site' as pagetype, name as title, name as route
		FROM
			`tabSite`
		WHERE
			team = '{team.name}' AND status NOT IN ('Archived')
		UNION ALL
		SELECT 'Bench' as pagetype, title as title, name as route
		FROM
			`tabRelease Group`
		WHERE
			team = '{team.name}' AND enabled = 1
		UNION ALL
		SELECT 'Server' as pagetype, name as title, name as route
		FROM
			`tabServer`
		WHERE
			team = '{team.name}' AND status = 'Active'
	"""

	return jingrow.db.sql(query, as_dict=True)


# Permissions
@jingrow.whitelist()
def get_permission_options(name, ptype):
	"""
	[{'pagetype': 'Site', 'name': 'ccc.jingrow.cloud', title: '', 'perms': 'jcloud.api.site.get'}, ...]
	"""
	from jcloud.jcloud.pagetype.jcloud_method_permission.jcloud_method_permission import (
		available_actions,
	)

	pagetypes = jingrow.get_all("Jcloud Method Permission", pluck="document_type", distinct=True)

	options = []
	for pagetype in pagetypes:
		pg = jingrow.qb.PageType(pagetype)
		perm_pg = jingrow.qb.PageType("Jcloud User Permission")
		subtable = (
			jingrow.qb.from_(perm_pg)
			.select("*")
			.where((perm_pg.user if ptype == "user" else perm_pg.group) == name)
		)

		query = (
			jingrow.qb.from_(pg)
			.left_join(subtable)
			.on(pg.name == subtable.document_name)
			.select(
				ValueWrapper(pagetype, alias="pagetype"),
				pg.name,
				pg.title if pagetype != "Site" else None,
				GROUP_CONCAT(subtable.action, alias="perms"),
			)
			.where(
				(pg.team == get_current_team())
				& ((pg.enabled == 1) if pagetype == "Release Group" else (pg.status != "Archived"))
			)
			.groupby(pg.name)
		)
		options += query.run(as_dict=True)

	return {"options": options, "actions": available_actions()}


@jingrow.whitelist()
def update_permissions(user, ptype, updated):
	values = []
	drop = []

	for pagetype, docs in updated.items():
		for pg, updated_perms in docs.items():
			ptype_cap = ptype.capitalize()
			old_perms = jingrow.get_all(
				"Jcloud User Permission",
				filters={
					"type": ptype_cap,
					ptype: user,
					"document_type": pagetype,
					"document_name": pg,
				},
				pluck="action",
			)
			# perms to insert
			add = set(updated_perms).difference(set(old_perms))
			values += [(jingrow.generate_hash(4), ptype_cap, pagetype, pg, user, a) for a in add]

			# perms to remove
			remove = set(old_perms).difference(set(updated_perms))
			drop += jingrow.get_all(
				"Jcloud User Permission",
				filters={
					"type": ptype_cap,
					ptype: user,
					"document_type": pagetype,
					"document_name": pg,
					"action": ("in", remove),
				},
				pluck="name",
			)

	if values:
		jingrow.db.bulk_insert(
			"Jcloud User Permission",
			fields=["name", "type", "document_type", "document_name", ptype, "action"],
			values=set(values),
			ignore_duplicates=True,
		)
	if drop:
		jingrow.db.delete("Jcloud User Permission", {"name": ("in", drop)})
	jingrow.db.commit()


@jingrow.whitelist()
def groups():
	return jingrow.get_all("Jcloud Permission Group", {"team": get_current_team()}, ["name", "title"])


@jingrow.whitelist()
def permission_group_users(name):
	if get_current_team() != jingrow.db.get_value("Jcloud Permission Group", name, "team"):
		jingrow.throw("You are not allowed to view this group")

	return jingrow.get_all("Jcloud Permission Group User", {"parent": name}, pluck="user")


@jingrow.whitelist()
def add_permission_group(title):
	pg = jingrow.get_pg(
		{"pagetype": "Jcloud Permission Group", "team": get_current_team(), "title": title}
	).insert(ignore_permissions=True)
	return {"name": pg.name, "title": pg.title}


@jingrow.whitelist()
@protected("Jcloud Permission Group")
def remove_permission_group(name):
	jingrow.db.delete("Jcloud User Permission", {"group": name})
	jingrow.delete_pg("Jcloud Permission Group", name)


@jingrow.whitelist()
@protected("Jcloud Permission Group")
def add_permission_group_user(name, user):
	pg = jingrow.get_pg("Jcloud Permission Group", name)
	pg.append("users", {"user": user})
	pg.save(ignore_permissions=True)


@jingrow.whitelist()
@protected("Jcloud Permission Group")
def remove_permission_group_user(name, user):
	pg = jingrow.get_pg("Jcloud Permission Group", name)
	for group_user in pg.users:
		if group_user.user == user:
			pg.remove(group_user)
			pg.save(ignore_permissions=True)
			break


@jingrow.whitelist()
def get_permission_roles():
	JcloudRole = jingrow.qb.PageType("Jcloud Role")
	JcloudRoleUser = jingrow.qb.PageType("Jcloud Role User")

	return (
		jingrow.qb.from_(JcloudRole)
		.select(
			JcloudRole.name,
			JcloudRole.admin_access,
			JcloudRole.allow_billing,
			JcloudRole.allow_apps,
			JcloudRole.allow_partner,
			JcloudRole.allow_site_creation,
			JcloudRole.allow_bench_creation,
			JcloudRole.allow_server_creation,
			JcloudRole.allow_webhook_configuration,
		)
		.join(JcloudRoleUser)
		.on((JcloudRole.name == JcloudRoleUser.parent) & (JcloudRoleUser.user == jingrow.session.user))
		.where(JcloudRole.team == get_current_team())
		.run(as_dict=True)
	)


@jingrow.whitelist()
def get_user_ssh_keys():
	return jingrow.db.get_list(
		"User SSH Key",
		{"is_removed": 0, "user": jingrow.session.user},
		["name", "ssh_fingerprint", "creation", "is_default"],
		order_by="creation desc",
	)


@jingrow.whitelist(allow_guest=True)
def is_2fa_enabled(user):
	return jingrow.db.get_value("User 2FA", user, "enabled")


@jingrow.whitelist(allow_guest=True)
@rate_limit(limit=5, seconds=60 * 60)
def verify_2fa(user, totp_code):
	user_totp_secret = get_decrypted_password("User 2FA", user, "totp_secret")
	verified = pyotp.TOTP(user_totp_secret).verify(totp_code)

	if not verified:
		jingrow.throw("Invalid 2FA code", jingrow.AuthenticationError)

	return verified


@jingrow.whitelist()
def get_2fa_qr_code_url():
	"""Get the QR code URL for 2FA provisioning"""

	if jingrow.db.exists("User 2FA", jingrow.session.user):
		user_totp_secret = get_decrypted_password("User 2FA", jingrow.session.user, "totp_secret")
	else:
		user_totp_secret = pyotp.random_base32()
		jingrow.get_pg(
			{
				"pagetype": "User 2FA",
				"user": jingrow.session.user,
				"totp_secret": user_totp_secret,
			}
		).insert()

	return pyotp.totp.TOTP(user_totp_secret).provisioning_uri(
		name=jingrow.session.user, issuer_name="Jingrow"
	)


@jingrow.whitelist()
def enable_2fa(totp_code):
	"""Enable 2FA for the user after verifying the TOTP code"""

	if jingrow.db.exists("User 2FA", jingrow.session.user):
		user_totp_secret = get_decrypted_password("User 2FA", jingrow.session.user, "totp_secret")
	else:
		jingrow.throw(f"2FA is not enabled for {jingrow.session.user}")

	if pyotp.totp.TOTP(user_totp_secret).verify(totp_code):
		jingrow.db.set_value("User 2FA", jingrow.session.user, "enabled", 1)
	else:
		jingrow.throw("Invalid TOTP code")


@jingrow.whitelist()
def disable_2fa(totp_code):
	"""Disable 2FA for the user after verifying the TOTP code"""

	if jingrow.db.exists("User 2FA", jingrow.session.user):
		user_totp_secret = get_decrypted_password("User 2FA", jingrow.session.user, "totp_secret")
	else:
		jingrow.throw(f"2FA is not enabled for {jingrow.session.user}")

	if pyotp.totp.TOTP(user_totp_secret).verify(totp_code):
		jingrow.db.set_value("User 2FA", jingrow.session.user, "enabled", 0)
	else:
		jingrow.throw("Invalid TOTP code")


# Not available for Telangana, Ladakh, and Other Territory
STATE_PINCODE_MAPPING = {
	"Jammu and Kashmir": (180, 194),
	"Himachal Pradesh": (171, 177),
	"Punjab": (140, 160),
	"Chandigarh": ((140, 140), (160, 160)),
	"Uttarakhand": (244, 263),
	"Haryana": (121, 136),
	"Delhi": (110, 110),
	"Rajasthan": (301, 345),
	"Uttar Pradesh": (201, 285),
	"Bihar": (800, 855),
	"Sikkim": (737, 737),
	"Arunachal Pradesh": (790, 792),
	"Nagaland": (797, 798),
	"Manipur": (795, 795),
	"Mizoram": (796, 796),
	"Tripura": (799, 799),
	"Meghalaya": (793, 794),
	"Assam": (781, 788),
	"West Bengal": (700, 743),
	"Jharkhand": (813, 835),
	"Odisha": (751, 770),
	"Chhattisgarh": (490, 497),
	"Madhya Pradesh": (450, 488),
	"Gujarat": (360, 396),
	"Dadra and Nagar Haveli and Daman and Diu": ((362, 362), (396, 396)),
	"Maharashtra": (400, 445),
	"Karnataka": (560, 591),
	"Goa": (403, 403),
	"Lakshadweep Islands": (682, 682),
	"Kerala": (670, 695),
	"Tamil Nadu": (600, 643),
	"Puducherry": ((533, 533), (605, 605), (607, 607), (609, 609), (673, 673)),
	"Andaman and Nicobar Islands": (744, 744),
	"Andhra Pradesh": (500, 535),
}

@jingrow.whitelist()
def update_profile_email(email):
	"""
	更新用户邮箱，并同步更新团队相关邮箱字段以及所有站点的通知邮箱
	"""
	if not email:
		jingrow.throw("邮箱不能为空")
	
	# 验证邮箱格式
	jingrow.utils.validate_email_address(email, True)
	
	# 更新用户邮箱
	user = jingrow.session.user
	user_pg = jingrow.get_pg("User", user)
	user_pg.email = email
	user_pg.save(ignore_permissions=True)
	
	# 更新团队邮箱字段
	team = get_current_team(get_pg=True)
	team.billing_email = email
	team.notify_email = email
	
	# 更新通信邮箱
	# 先删除现有的邮箱记录
	to_remove = []
	for i, comm_email in enumerate(team.communication_emails):
		if comm_email.type in ["invoices", "marketplace_notifications"]:
			to_remove.append(i)
	
	# 从后向前删除，避免索引问题
	for i in sorted(to_remove, reverse=True):
		team.communication_emails.pop(i)
	
	# 添加新的通信邮箱
	team.append("communication_emails", {
		"type": "invoices", 
		"value": email
	})
	
	team.append("communication_emails", {
		"type": "marketplace_notifications", 
		"value": email
	})
	
	team.save(ignore_permissions=True)
	
	# 更新所有属于该团队的站点的通知邮箱
	sites = jingrow.get_all(
		"Site", 
		filters={"team": team.name},
		pluck="name"
	)
	
	for site_name in sites:
		jingrow.db.set_value("Site", site_name, "notify_email", email)
	
	# 提交数据库更改
	jingrow.db.commit()
	
	return {
		"user": user_pg,
		"team": team
	}

@jingrow.whitelist()
def verify_api_credentials_and_balance(api_key: str, api_secret: str, api_name: str):

    try:
        # 获取当前用户（管理员）的API信息
        admin_user = jingrow.session.user
        
        # 验证管理员权限
        if admin_user != "Administrator":
            return {
                "success": False,
                "message": "只有管理员用户才能访问此API"
            }
            
        # 验证用户的API密钥
        user = jingrow.db.get_value(
            "User",
            {"api_key": api_key},
            ["name", "enabled", "api_secret"]
        )
        
        if not user:
            return {
                "success": False,
                "message": "无效的API密钥"
            }
            
        # 验证用户的API密钥
        stored_secret = get_decrypted_password("User", user[0], "api_secret")
        if stored_secret != api_secret:
            return {
                "success": False,
                "message": "无效的API密钥"
            }
            
        if not user[1]:  # 检查用户是否启用
            return {
                "success": False,
                "message": "用户账户已禁用"
            }
            
        # 获取用户团队
        team = jingrow.db.get_value(
            "Team",
            {"user": user[0]},
            ["name", "enabled"]
        )
        
        if not team:
            return {
                "success": False,
                "message": "未找到用户团队"
            }
            
        if not team[1]:  # 检查团队是否启用
            return {
                "success": False,
                "message": "团队账户已禁用"
            }
            
        # 获取团队余额
        team_pg = jingrow.get_pg("Team", team[0])
        balance = team_pg.get_balance()
        
        # 获取API价格
        price = jingrow.db.get_value("Api Pricing", {"api_name": api_name}, "price") or 0
        if price <= 0:
            return {
                "success": False,
                "message": "API价格未设置"
            }
        
        # 检查余额是否足够
        has_sufficient_balance = balance >= price
        
        if not has_sufficient_balance:
            return {
                "success": False,
                "message": "余额不足"
            }
            
        return {
            "success": True,
            "message": "验证成功"
        }
        
    except Exception as e:
        return {
            "success": False,
            "message": f"验证过程发生错误: {str(e)}"
        }

@jingrow.whitelist()
def deduct_api_usage_fee(api_key: str, api_secret: str, api_name: str, usage_count: int = 1):

    try:        
        # 获取当前用户（管理员）
        admin_user = jingrow.session.user
        
        # 验证管理员权限
        if admin_user != "Administrator":
            jingrow.log_error("API扣费", f"非管理员用户尝试访问API: {admin_user}")
            return {
                "success": False,
                "message": "只有管理员用户才能访问此API"
            }
            
        # 验证用户的API密钥
        user = jingrow.db.get_value(
            "User",
            {"api_key": api_key},
            ["name", "enabled", "api_secret"]
        )
        
        if not user:
            jingrow.log_error("API扣费", f"无效的API密钥: {api_key}")
            return {
                "success": False,
                "message": "无效的API密钥"
            }
                    
        # 验证用户的API密钥
        stored_secret = get_decrypted_password("User", user[0], "api_secret")
        if stored_secret != api_secret:
            return {
                "success": False,
                "message": "无效的API密钥"
            }
            
        if not user[1]:  # 检查用户是否启用
            return {
                "success": False,
                "message": "用户账户已禁用"
            }
            
        # 获取用户团队
        team = jingrow.db.get_value(
            "Team",
            {"user": user[0]},
            ["name", "enabled"]
        )
        
        if not team:
            return {
                "success": False,
                "message": "未找到用户团队"
            }
                    
        if not team[1]:  # 检查团队是否启用
            return {
                "success": False,
                "message": "团队账户已禁用"
            }
        
        # 获取API价格及描述
        price = jingrow.db.get_value("Api Pricing", {"api_name": api_name}, "price") or 0
        api_description = jingrow.db.get_value("Api Pricing", {"api_name": api_name}, "description") or api_name
        
        if price <= 0:
            return {
                "success": False,
                "message": "API价格未设置"
            }
        
        # 计算总费用
        total_price = price * usage_count
                    
        # 创建余额交易记录（扣款）
        balance_transaction = jingrow.get_pg({
            "pagetype": "Balance Transaction",
            "team": team[0],  # 使用API的团队
            "type": "Adjustment",
            "source": "Prepaid Credits",
            "amount": -1 * float(total_price),  # 使用负数表示扣减
            "description": f"{api_description} x {usage_count}次",
        })
        
        # 保存交易记录
        balance_transaction.insert(ignore_permissions=True)
        balance_transaction.submit()
        
        jingrow.db.commit()        
        return {
            "success": True,
            "message": "扣费成功"
        }
        
    except Exception as e:
        error_msg = f"扣费过程发生错误: {str(e)}"
        jingrow.log_error("API扣费错误", error_msg)
        return {
            "success": False,
            "message": error_msg
        }
	
	