import frappe
from frappe.model.db_query import DatabaseQuery
from frappe.utils import flt, nowdate

from erpnext.stock.utils import get_stock_balance


@frappe.whitelist()
def get_data(
	item_code=None,
	warehouse=None,
	parent_warehouse=None,
	company=None,
	start=0,
	sort_by="stock_capacity",
	sort_order="desc",
):
	"""Return data to render the warehouse capacity dashboard."""
	filters = get_filters(item_code, warehouse, parent_warehouse, company)

	no_permission, filters = get_warehouse_filter_based_on_permissions(filters)
	if no_permission:
		return []

	capacity_data = get_warehouse_capacity_data(filters, start)

	asc_desc = -1 if sort_order == "desc" else 1
	capacity_data = sorted(capacity_data, key=lambda i: (i[sort_by] * asc_desc))

	return capacity_data


def get_filters(item_code=None, warehouse=None, parent_warehouse=None, company=None):
	filters = [["disable", "=", 0]]
	if item_code:
		filters.append(["item_code", "=", item_code])
	if warehouse:
		filters.append(["warehouse", "=", warehouse])
	if company:
		filters.append(["company", "=", company])
	if parent_warehouse:
		lft, rgt = frappe.db.get_value("Warehouse", parent_warehouse, ["lft", "rgt"])
		warehouses = frappe.db.sql_list(
			"""
			select name from `tabWarehouse`
			where lft >=%s and rgt<=%s
		""",
			(lft, rgt),
		)
		filters.append(["warehouse", "in", warehouses])
	return filters


def get_warehouse_filter_based_on_permissions(filters):
	try:
		# check if user has any restrictions based on user permissions on warehouse
		if DatabaseQuery("Warehouse", user=frappe.session.user).build_match_conditions():
			filters.append(["warehouse", "in", [w.name for w in frappe.get_list("Warehouse")]])
		return False, filters
	except frappe.PermissionError:
		# user does not have access on warehouse
		return True, []


def get_warehouse_capacity_data(filters, start):
	capacity_data = frappe.db.get_all(
		"Putaway Rule",
		fields=["item_code", "warehouse", "stock_capacity", "company"],
		filters=filters,
		limit_start=start,
		limit_page_length="11",
	)

	for entry in capacity_data:
		balance_qty = get_stock_balance(entry.item_code, entry.warehouse, nowdate()) or 0
		entry.update(
			{
				"actual_qty": balance_qty,
				"percent_occupied": flt((flt(balance_qty) / flt(entry.stock_capacity)) * 100, 0),
			}
		)

	return capacity_data
