/*
 * cntlr_apis.c - public APIs available to Controller plugins.
 *
 * Copyright (C) 2025 Genexis Sweden AB.
 *
 * See LICENSE file for source code license information.
 *
 */
#include "cntlr.h"
#include "sta.h"
#include "acs.h"
#include "cntlr_apis.h"


int cntlr_register_module(void **controller, void *module)
{
	//TODO
	return -1;
}

void cntlr_unregister_module(void *module)
{
	//TODO
}

struct wifi_radio_element *cntlr_get_radio_element(void *cntlr, uint8_t *ruid)
{
	struct controller *c = (struct controller *)cntlr;
	struct netif_radio *r;

	r = cntlr_find_radio(c, ruid);
	return r ? r->radio_el : NULL;
}

struct wifi_radio_element *cntlr_get_radio_element_by_bssid(void *cntlr, uint8_t *bssid)
{
	struct controller *c = (struct controller *)cntlr;
	struct netif_radio *r = NULL;
	struct netif_iface *p = NULL;
	struct node *n = NULL;

	list_for_each_entry(n, &c->nodelist, list) {
		list_for_each_entry(r, &n->radiolist, list) {
			list_for_each_entry(p, &r->iflist, list) {
				if (!memcmp(p->bss->bssid, bssid, 6))
					return r->radio_el;
			}
		}
	}

	return NULL;
}

struct wifi_radio_element *cntlr_get_radio_element_in_node_by_band(void *cntlr,
								   uint8_t *node_almacaddr,
								   enum wifi_band band)
{
	struct controller *c = (struct controller *)cntlr;
	struct netif_radio *r = NULL;
	struct node *n;

	n = cntlr_find_node(c, node_almacaddr);
	if (!n)
		return NULL;

	r = cntlr_find_radio_in_node_by_band(c, n, band);
	return r ? r->radio_el : NULL;
}

struct wifi_bss_element *cntlr_get_backhaul_bss_element_in_node(void *cntlr,
								uint8_t *node_almacaddr,
								enum wifi_band band)
{
	struct controller *c = (struct controller *)cntlr;
	struct netif_radio *r = NULL;
	struct node *n;

	n = cntlr_find_node(c, node_almacaddr);
	if (!n)
		return NULL;

	r = cntlr_find_radio_in_node_by_band(c, n, band);
	if (r) {
		struct netif_iface *p = NULL;

		list_for_each_entry(p, &r->iflist, list) {
			if (p->bss->is_bbss)
				return p->bss;
		}
	}

	return NULL;
}

struct wifi_bss_element *cntlr_get_fronthaul_bss_element_in_node(void *cntlr,
								 uint8_t *node_almacaddr,
								 enum wifi_band band)
{
	struct controller *c = (struct controller *)cntlr;
	struct netif_radio *r = NULL;
	struct node *n;

	n = cntlr_find_node(c, node_almacaddr);
	if (!n)
		return NULL;

	r = cntlr_find_radio_in_node_by_band(c, n, band);
	if (r) {
		struct netif_iface *p = NULL;

		list_for_each_entry(p, &r->iflist, list) {
			if (p->bss->is_fbss)
				return p->bss;
		}
	}

	return NULL;
}

enum wifi_band cntlr_get_bss_band(void *cntlr, uint8_t *bssid)
{
	struct controller *c = (struct controller *)cntlr;
	struct netif_iface *bss;

	bss = cntlr_find_bss(c, bssid);
	if (bss && bss->radio && bss->radio->radio_el)
		return bss->radio->radio_el->band;

	return BAND_UNKNOWN;
}

uint8_t cntlr_get_bss_opclass(void *cntlr, uint8_t *bssid)
{
	struct controller *c = (struct controller *)cntlr;
	struct netif_iface *bss;

	bss = cntlr_find_bss(c, bssid);
	if (bss && bss->radio && bss->radio->radio_el)
		return ctrl_radio_cur_opclass_id(bss->radio->radio_el);

	return 0;
}

uint8_t cntlr_get_bss_channel(void *cntlr, uint8_t *bssid)
{
	struct controller *c = (struct controller *)cntlr;
	struct netif_iface *bss;

	bss = cntlr_find_bss(c, bssid);
	if (bss && bss->radio && bss->radio->radio_el)
		return ctrl_radio_cur_opclass_ctrl_chan(bss->radio->radio_el);

	return 0;
}

uint32_t cntlr_get_bss_bandwidth(void *cntlr, uint8_t *bssid)
{
	struct controller *c = (struct controller *)cntlr;
	struct netif_iface *bss;

	bss = cntlr_find_bss(c, bssid);
	if (bss && bss->radio && bss->radio->radio_el)
		return ctrl_radio_cur_opclass_max_bw(bss->radio->radio_el);

	return 0;
}

struct wifi_sta_element *cntlr_get_sta_element(void *cntlr, uint8_t *macaddr)
{
	struct controller *c = (struct controller *)cntlr;
	struct sta *s;

	s = cntlr_find_sta(c->sta_table, macaddr);
	return s ? s->de_sta : NULL;
}

void *cntlr_get_sta_steer_data(void *cntlr, uint8_t *macaddr)
{
	struct controller *c = (struct controller *)cntlr;
	struct sta *s;

	s = cntlr_find_sta(c->sta_table, macaddr);
	return s ? s->steer_data : NULL;
}

int cntlr_get_agent_id(void *cntlr, uint8_t *if_macaddr, uint8_t *agent_almacaddr)
{
	struct controller *c = (struct controller *)cntlr;
	struct netif_iface *iface = NULL;
	int ret = -1;

	iface = cntlr_find_bss(c, if_macaddr);
	if (iface && agent_almacaddr) {
		memcpy(agent_almacaddr, iface->agent->almacaddr, 6);
		ret = 0;
	}

	return ret;
}

int cntlr_get_bsta_agent_id(void *cntlr, uint8_t *bsta_macaddr, uint8_t *bsta_agent_almacaddr)
{
	struct controller *c = (struct controller *)cntlr;
	struct sta *s= NULL;
	int ret = -1;

	s = cntlr_find_sta(c->sta_table, bsta_macaddr);
	if (s && s->is_bsta && bsta_agent_almacaddr) {
		memcpy(bsta_agent_almacaddr, s->bsta_agent_almacaddr, 6);
		ret = 0;
	}

	return ret;
}

bool cntlr_is_sta_bsta(void *cntlr, uint8_t *macaddr)
{
	struct controller *c = (struct controller *)cntlr;
	struct sta *s;

	s = cntlr_find_sta(c->sta_table, macaddr);
	return s->is_bsta ? true : false;
}

int cntlr_estimate_max_thput_for_node(void *cntlr, uint8_t *node_almacaddr)
{
	struct controller *c = (struct controller *)cntlr;
	int ret;

	ret = cntlr_estimate_max_throughput_for_node(c, node_almacaddr);
	return ret;
}

int cntlr_get_max_thput_estimate_for_node(void *cntlr, uint8_t *node_almacaddr)
{
	struct controller *c = (struct controller *)cntlr;
	struct node *n;

	n = cntlr_find_node(c, node_almacaddr);
	if (!n)
		return -1;

	return n->est_thput_dl > 0 && n->est_thput_dl < UINT32_MAX ? n->est_thput_dl : -1;
}

char *cntlr_get_topology_json_string(void *cntlr)
{
	return cntlr_get_topology(cntlr);
}
