import { deserialize, deserializeWithContextAndRun, formatContactName, Id, JsonObject, tryToDeserializeAndRun } from '@win2win/shared';
import { getValue, useFetch } from '@win2win/shared-ui';
import { camelCase, mapKeys, omit, orderBy } from 'lodash';
import { Tab } from 'src/components/common-ww/btns/tabs';
import { useAuth } from 'src/composables/useAuth';
import { GlobalAction, LayoutContext, LayoutGroup, LayoutGroupMainLayout, LayoutParams, LayoutType, LayoutView, Popup, Widget } from 'src/models';
import { useDynamicLayoutStore } from 'src/store/useDynamicLayoutStore';
import { Component, computed, MaybeRef, ref, Ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import { useStore } from 'vuex';
import { getWidget as gesRawWidget } from './helpers';
import MockCardWidget from './MockCardWidget.vue';
import { useCaptacionLite, useClienteLite, useDelegacionLite, useLiquidacionLite, usePartnerLite, useProductoLite, useProveedorLite, useUsuarioLite } from './useStoreLite';
export type AppWidget = { component: Component; props: LayoutWidgetProps };
export type AppLayoutView = LayoutView & { widgets: AppWidget[] };

export function useLayout(_context: MaybeRef<LayoutContext>, type: LayoutType, idGama?: Ref<Id | null>, useModel = false) {
  const dynamicLayoutStore = useDynamicLayoutStore();
  const { rol, perfil } = useAuth();
  const context = computed<LayoutContext>(() => getValue(_context));
  const { data: captacion } = useCaptacionLite();
  const { data: proveedor } = useProveedorLite();
  const { data: liquidacion } = useLiquidacionLite();
  const { data: usuario } = useUsuarioLite();
  const { data: delegacion } = useDelegacionLite();
  const { data: producto } = useProductoLite();
  const { data: cliente } = useClienteLite();
  const { data: partner } = usePartnerLite();
  const dataLite = computed(
    () =>
      ({
        captacion: captacion.value,
        proveedor: proveedor.value,
        liquidacion: liquidacion.value,
        usuario: usuario.value,
        delegacion: delegacion.value,
        producto: producto.value,
        cliente: cliente.value,
        partner: partner.value,
      }[context.value])
  );

  const store = useStore();
  const computedIdGama = computed(() => {
    return idGama?.value || dataLite.value?.GAMA?.ID_GAMA || dataLite.value?.ID_GAMA;
  });
  const gama = computed(() => (store.getters['gamas/gamasFlat'] || []).find((g) => g.ID_GAMA === computedIdGama.value));
  const queryKey = computed(() => ['layouts', { idGama: computedIdGama.value, context: context.value, type }]);
  const path = computed(() => (computedIdGama.value ? `gamas/${computedIdGama.value}/layouts` : ''));
  const { data: layoutGroup, fetching } = useFetch<LayoutGroup | null>(queryKey, path, { byEqualCol: { CONTEXT: context.value, TYPE: type } }, (v) => (v.length ? formatKeys(v[0]) : null), {
    enabled: computed(() => !!computedIdGama.value),
  });

  const layoutParams = computed<LayoutParams>(() => ({
    rol: rol.value,
    data: dataLite.value || {},
    perfil: perfil.value,
    id: dataLite.value?.[`ID_${context.value.toUpperCase()}`] || null,
    gama: gama.value,
    estado: dataLite.value?.ESTADO || null,
  }));

  const layout = computed(() => {
    const group = layoutGroup.value;
    if (!group) return [];
    return orderBy(
      (group.views || []).map((view: LayoutView) => {
        const visible = tryToDeserializeAndRun(view.visibilityFn, layoutParams.value, true);
        return { ...view, visible };
      }) || [],
      'position'
    );
  });

  const popups = computed<Popup[]>(() => {
    const group = layoutGroup.value;
    if (!group?.popups) return [];
    return group.popups.filter((p) => p.enabled);
  });

  const globalActions = computed<GlobalAction[]>(() => {
    const group = layoutGroup.value;
    if (!group?.globalActions) return [];
    return group.globalActions?.filter((action) => !!action.enabled) || [];
  });

  const viewModel = ref<string>('');

  const currentView = computed(() => {
    const view = layout.value.find((l) => (viewModel.value ? l.view === viewModel.value : true) && tryToDeserializeAndRun(l.visibilityFn, layoutParams.value, true));
    if (!view) return null;
    const widgets = view.widgets.map((w) => getWidget(w)).filter((w) => w !== null && !!w.props.enabled);
    return { ...view, widgets } as AppLayoutView;
  });

  const getWidget = (widget: Widget) => {
    if (widget.condition) {
      if (!layoutParams.value) return null;
      const enabled = deserialize(widget.condition, { context: layoutParams.value, run: true });
      if (!enabled) return null;
    }

    return {
      props: omit(widget, 'code'),
      component: gesRawWidget(widget.code) || MockCardWidget,
    };
  };

  const tabs = computed(() => {
    if (type !== 'detalle') return [];
    return layout.value
      .filter((ctx) => {
        const hasTab = !!ctx.tab;
        return hasTab && ctx.visible;
      })
      .map(({ tab }) => tab as Tab);
  });

  watch(computedIdGama, (value) => {
    if (!value) return;
    store.dispatch('gamas/fetchLayouts', { idGama: value });
  });

  const functions = {
    formatName: formatContactName,
    formatContactName,
  };

  const mainLayout = computed(() => {
    const rawLayout = layoutGroup.value?.layout || null;
    if (!rawLayout) return null;

    const context = { ...layoutParams.value, ...functions };
    const title = deserializeWithContextAndRun(rawLayout.title, context);
    const backButton = deserializeWithContextAndRun(rawLayout.backButton, context);
    const allowNavigation = rawLayout.allowNavigation ?? false;
    return { title, backButton, allowNavigation } as LayoutGroupMainLayout;
  });

  const firstLayout = computed<LayoutView>(() => layout.value?.[0] || {});

  watch(
    currentView,
    (val) => {
      dynamicLayoutStore.setCurrentView(val, { context: context.value, type });
    },
    { immediate: true }
  );

  watch(
    tabs,
    (val) => {
      dynamicLayoutStore.setTabs(val, { context: context.value, type });
    },
    { immediate: true }
  );

  watch(
    layoutParams,
    (val) => {
      dynamicLayoutStore.setContextParams(val, { context: context.value, type });
    },
    { immediate: true }
  );

  const route = useRoute();
  watch(
    () => route.path,
    (val) => {
      if (useModel) return;
      const pathLevels = val.split('/').slice(1).length;
      if (pathLevels < 3) return;
      viewModel.value = val.split('/').pop() || 'estado';
    },
    { immediate: true }
  );

  return { layout, popups, tabs, layoutParams, currentView, globalActions, idGama: computedIdGama, gama, mainLayout, fetching, viewModel, firstLayout };
}

function formatKeys(layoutGroup: JsonObject) {
  const toCamelCase = (array: JsonObject[]) => array.map((el) => mapKeys(el, (_, key) => camelCase(key)));
  const group = mapKeys(layoutGroup, (_, key) => camelCase(key));
  group.views = toCamelCase(group.views);
  group.popups = toCamelCase(group.popups);
  group.globalActions = toCamelCase(group.globalActions);
  return group as LayoutGroup;
}

export type LayoutWidgetProps = Omit<Widget, 'code'>;
