import json

import jingrow
from jingrow.client import set_value
from jingrow.utils.background_jobs import enqueue


# ===== IMAP Sync Helpers =====

IMAP_FOLDER_MAP = {
	"Trash": "Trash",
	"Spam": "Spam",
	"Open": "INBOX",
	"Draft": "Drafts",
}


def _sync_imap_move(email_name, dest_folder):
	"""Best-effort: move email on IMAP server asynchronously.

	Only applies to received emails with a valid UID.
	Failures are logged but do not block the local DB operation.
	"""
	uid, email_account, imap_folder = jingrow.db.get_value(
		"Email", email_name, ["uid", "email_account", "imap_folder"]
	) or (None, None, None)

	if not uid or uid == -1 or not email_account:
		return

	src = imap_folder or "INBOX"
	dest = IMAP_FOLDER_MAP.get(dest_folder, dest_folder)

	enqueue(
		"jingrow.email.inbox._do_imap_move",
		queue="short",
		email_account=email_account,
		uid=str(uid),
		src=src,
		dest=dest,
	)


def _do_imap_move(email_account, uid, src, dest):
	"""Background job: perform IMAP MOVE on server."""
	try:
		account = jingrow.get_pg("Email Account", email_account)
		if not account.use_imap or not account.enable_incoming:
			return
		email_server = account.get_incoming_server(in_receive=True)
		try:
			email_server.move_to_folder(src, uid, dest)
		finally:
			try:
				email_server.logout()
			except Exception:
				pass
	except Exception:
		jingrow.log_error(f"IMAP move failed: {uid} from {src} to {dest}")


@jingrow.whitelist()
def get_email_accounts(user=None):
	if not user:
		user = jingrow.session.user

	email_accounts = []

	accounts = jingrow.get_all(
		"User Email",
		filters={"parent": user},
		fields=["email_account", "email_id", "enable_outgoing"],
		distinct=True,
		order_by="idx",
	)

	if not accounts:
		return {"email_accounts": [], "all_accounts": ""}

	all_accounts = ",".join(account.get("email_account") for account in accounts)
	if len(accounts) > 1:
		email_accounts.append({"email_account": all_accounts, "email_id": "All Accounts"})
	email_accounts.extend(accounts)

	email_accounts.extend(
		[
			{"email_account": "Sent", "email_id": "Sent Mail"},
			{"email_account": "Spam", "email_id": "Spam"},
			{"email_account": "Trash", "email_id": "Trash"},
		]
	)

	return {"email_accounts": email_accounts, "all_accounts": all_accounts}


@jingrow.whitelist()
def create_email_flag_queue(names, action):
	"""create email flag queue to mark email either as read or unread"""

	def mark_as_seen_unseen(name, action):
		pg = jingrow.get_pg("Email", name)
		if action == "Read":
			pg.add_seen()
		else:
			_seen = json.loads(pg._seen or "[]")
			_seen = [user for user in _seen if jingrow.session.user != user]
			pg.db_set("_seen", json.dumps(_seen), update_modified=False)

	if not all([names, action]):
		return

	for name in json.loads(names or []):
		uid, seen_status, email_account = jingrow.db.get_value(
			"Email", name, ["uid", "seen", "email_account"]
		)
		if not uid:
			uid = -1
		if not seen_status:
			seen_status = 0

		# can not mark email SEEN or UNSEEN without uid
		if not uid or uid == -1:
			continue

		seen = 1 if action == "Read" else 0
		# check if states are correct
		if (action == "Read" and seen_status == 0) or (action == "Unread" and seen_status == 1):
			create_new = True
			email_flag_queue = jingrow.db.sql(
				"""select name, action from `tabEmail Flag Queue`
				where email = %(name)s and is_completed=0""",
				{"name": name},
				as_dict=True,
			)

			for queue in email_flag_queue:
				if queue.action != action:
					jingrow.delete_pg("Email Flag Queue", queue.name, ignore_permissions=True)
				elif queue.action == action:
					# Read or Unread request for email is already available
					create_new = False

			if create_new:
				flag_queue = jingrow.get_pg(
					{
						"uid": uid,
						"action": action,
						"email": name,
						"pagetype": "Email Flag Queue",
						"email_account": email_account,
					}
				)
				flag_queue.save(ignore_permissions=True)
				jingrow.db.set_value("Email", name, "seen", seen, update_modified=False)
				mark_as_seen_unseen(name, action)


@jingrow.whitelist()
def mark_as_closed_open(email: str, status: str):
	"""Set status to open or close"""
	pg = jingrow.get_pg("Email", email)
	pg.set("status", status)
	pg.save(ignore_permissions=True)


@jingrow.whitelist()
def move_email(email: str, email_account: str):
	"""Move email to another email account."""
	pg = jingrow.get_pg("Email", email)
	pg.set("email_account", email_account)
	pg.save(ignore_permissions=True)


@jingrow.whitelist()
def get_all_email_accounts():
	"""Get all enabled incoming email accounts, excluding current user's own accounts."""
	user = jingrow.session.user

	# Current user's own accounts (to exclude)
	own_accounts = jingrow.get_all(
		"User Email",
		filters={"parent": user},
		fields=["email_account"],
		pluck="email_account",
	)
	own_set = set(own_accounts)

	# All enabled incoming accounts
	accounts = jingrow.get_all(
		"Email Account",
		filters={"enable_incoming": 1},
		fields=["name", "email_id", "email_account_name"],
		order_by="name",
	)

	# Filter out current user's own accounts
	others = [a for a in accounts if a.name not in own_set]
	return {"email_accounts": others}


@jingrow.whitelist()
def assign_email(email: str, email_account: str):
	"""Assign email to another user's email account."""
	pg = jingrow.get_pg("Email", email)
	pg.set("email_account", email_account)
	pg.save(ignore_permissions=True)


@jingrow.whitelist()
def mark_as_trash(email: str):
	"""Set email status to trash and sync to IMAP server."""
	pg = jingrow.get_pg("Email", email)
	pg.set("email_status", "Trash")
	pg.save(ignore_permissions=True)
	_sync_imap_move(email, "Trash")


@jingrow.whitelist()
def mark_as_spam(email: str, sender: str):
	"""Set email status to spam and sync to IMAP server."""
	email_rule = jingrow.db.get_value("Email Rule", {"email_id": sender})
	if not email_rule:
		jingrow.get_pg({"pagetype": "Email Rule", "email_id": sender, "is_spam": 1}).insert(
			ignore_permissions=True
		)
	pg = jingrow.get_pg("Email", email)
	pg.set("email_status", "Spam")
	pg.save(ignore_permissions=True)
	_sync_imap_move(email, "Spam")


@jingrow.whitelist()
def mark_as_draft(email: str):
	"""Set email status to draft and sync to IMAP server."""
	pg = jingrow.get_pg("Email", email)
	pg.set("email_status", "Draft")
	pg.save(ignore_permissions=True)
	_sync_imap_move(email, "Draft")


@jingrow.whitelist()
def mark_as_open(email: str):
	"""Restore email status to open (from Spam/Trash/Draft) and sync to IMAP server."""
	pg = jingrow.get_pg("Email", email)
	pg.set("email_status", "Open")
	pg.save(ignore_permissions=True)
	_sync_imap_move(email, "INBOX")


def link_communication_to_document(pg, reference_pagetype, reference_name, ignore_communication_links):
	if not ignore_communication_links:
		pg.reference_pagetype = reference_pagetype
		pg.reference_name = reference_name
		pg.status = "Linked"
		pg.save(ignore_permissions=True)


@jingrow.whitelist()
def permanent_delete_emails(names):
	"""Archive emails in jingrow DB (system-level archive, invisible to normal users).

	Sets email_status to 'Archived'. IMAP server auto-purges Spam/Trash folders
	periodically, so no explicit IMAP delete is needed.
	"""
	if isinstance(names, str):
		names = json.loads(names)

	for name in names:
		# Archive in system (keep record, only admin can access)
		try:
			jingrow.db.set_value("Email", name, "email_status", "Archived", update_modified=False)
		except Exception:
			pass


@jingrow.whitelist()
def purge_archived_emails(names):
	"""Permanently delete archived emails from DB (admin only).

	Only emails with email_status='Archived' can be purged.
	Requires System Manager or Administrator role.
	"""
	if isinstance(names, str):
		names = json.loads(names)

	# Permission check: only System Manager or Administrator can purge
	if not ("System Manager" in jingrow.get_roles() or "Administrator" in jingrow.get_roles()):
		jingrow.throw(jingrow._("Only System Manager or Administrator can purge archived emails"))

	for name in names:
		# Only purge emails that are already Archived
		email_status = jingrow.db.get_value("Email", name, "email_status")
		if email_status != "Archived":
			continue
		try:
			jingrow.delete_pg("Email", name, ignore_permissions=True)
		except Exception:
			pass
