import axios from 'axios';
import { Instance, types } from 'mobx-state-tree';

type _WidgetParams = Record<string, any> | null;

export const WidgetParams = types.frozen<_WidgetParams>();

type _DataLoaderParams = Record<string, any> | null;

export const DataLoaderParams = types.frozen<_DataLoaderParams>();

export const Widget = types
  .model({
    type: types.string,
    id: types.string,
    title: types.string,
    collapsed: types.maybe(types.boolean),
    visible: types.boolean,
    widgetParams: types.maybe(WidgetParams),
    dataLoaderParams: types.maybe(DataLoaderParams),
    loaded: false,
    data: types.maybe(types.frozen<any>()),
    dashboardId: types.maybe(types.string),
  })
  .actions((self) => {
    return {
      show: () => {
        self.visible = false;
      },
      hide: () => {
        self.visible = true;
      },
      toggle: () => {
        self.visible = !self.visible;
      },
      setData: (data: any) => {
        self.loaded = true;
        self.data = data;
      },
      setDashboardId: (dashboardId: string) => {
        self.dashboardId = dashboardId;
      },
    };
  });

export type IWidget = Instance<typeof Widget>;

export function createWidgetStore(
  id: string,
  type: string,
  title: string,
  collapsed = false,
  widgetParams?: _WidgetParams,
  dataLoaderParams?: _DataLoaderParams,
): IWidget {
  return Widget.create({
    id: id,
    type: type,
    title: title,
    collapsed: collapsed,
    visible: !collapsed,
    widgetParams: widgetParams,
    dataLoaderParams: dataLoaderParams,
  });
}

export const Data = types.model({
  widgets: types.array(Widget),
  title: types.maybe(types.string),
});

export const Dashboard = types
  .model({
    loaded: types.boolean,
    id: types.string,
    data: types.maybe(Data),
  })
  .actions((self) => {
    return {
      setData: (data: any) => {
        if (data.widgets) {
          for (let i = 0; i < data.widgets.length; i++) {
            const widget = data.widgets[i];
            widget.visible = !widget.collapsed;
          }
        }
        self.data = data;
        self.loaded = true;
      },
      setWidgetsData: (data: any) => {
        for (let i = 0; i < data.length; i++) {
          const widgetData = data[i]?.data;
          const widgetId = data[i]?.widgetId;
          if (!widgetId || !widgetData) continue;

          const widgets = self.data?.widgets;
          if (!widgets || widgets.length <= 0) return;

          const widget = widgets.find((w) => w.id == widgetId);
          if (!widget) continue;

          widget.setData(widgetData);
        }
      },
      setWidgetData: (widgetId: string, data: any) => {
        const widget = self.data?.widgets.find((w) => w.id == widgetId);
        if (!widget) return;
        widget.setData(data);
      },
    };
  });

export type IDashboard = Instance<typeof Dashboard>;

export async function DashboardLoadData(store: IDashboard): Promise<void> {
  const url = `${process.env.REACT_APP_BACKEND}api/dashboard/${store.id}`;
  const resp = await axios.get(url);
  if (!resp.data) return;
  store.setData(resp.data);
}

export async function LoadDataForWidgets(store: IDashboard): Promise<void> {
  const url = `${process.env.REACT_APP_BACKEND}api/dashboard/${store.id}/load-data`;
  const resp = await fetch(url);
  if (resp && resp.ok) {
    const data = await resp.json();
    store.setWidgetsData(data);
  }
}

export async function LoadDataForWidget(
  store: IDashboard,
  widgetId: string,
): Promise<void> {
  const url = `${process.env.REACT_APP_BACKEND}api/dashboard/${store.id}/load-data/${widgetId}`;
  const resp = await fetch(url);
  if (resp && resp.ok) {
    const data = await resp.json();
    store.setWidgetData(widgetId, data);
  }
  return;
}

export async function WidgetLoadData(widget: IWidget): Promise<void> {
  if (!widget.dashboardId) return;
  const url = `${process.env.REACT_APP_BACKEND}api/dashboard/${widget.dashboardId}/load-data/${widget.id}`;
  const resp = await fetch(url);
  if (resp && resp.ok) {
    const data = await resp.json();
    if (data) {
      widget.setData(data);
    }
  }
}
