import { ref, computed } from "vue";
import { defineStore } from "pinia";
import { scriptsApi } from "../api/modules/scripts";
import { useAsyncRequest } from "../composables/useAsyncRequest";

export const useScriptsStore = defineStore("scripts", () => {
  const actions = ref([]);
  const regular = ref([]);
  const scopes = ref([]);
  const runningAliases = ref(new Set());
  const refreshingIndicators = ref(new Set());
  const lastRunResult = ref(null);
  const currentScopeCode = ref("");

  const actionsRequest = useAsyncRequest();
  const regularRequest = useAsyncRequest();
  const scopesRequest = useAsyncRequest();
  const scopeCodeRequest = useAsyncRequest();

  const totalActions = computed(() => actions.value.length);
  const totalRegular = computed(() => regular.value.length);
  const totalScopes = computed(() => scopes.value.length);
  const isRunning = computed(() => (alias) => runningAliases.value.has(alias));
  const isRefreshingIndicator = computed(() => (alias) => refreshingIndicators.value.has(alias));
  const actionByAlias = computed(() => (alias) => actions.value.find((s) => s.alias === alias) || null);
  const regularByAlias = computed(() => (alias) => regular.value.find((s) => s.alias === alias) || null);
  const scopeByName = computed(() => (name) => scopes.value.find((s) => s.name === name) || null);
  const actionsByScope = computed(() => (scopeName) => actions.value.filter((s) => s.scope === scopeName));
  const regularByScope = computed(() => (scopeName) => regular.value.filter((s) => s.scope === scopeName));

  async function loadActions() {
    return actionsRequest.execute(async (signal) => {
      const result = await scriptsApi.actionsList({ signal });
      if (result.ok) {
        actions.value = result.data?.data?.scripts || [];
      }
      return result;
    });
  }

  async function refreshAction(alias) {
    refreshingIndicators.value = new Set(refreshingIndicators.value).add(alias);
    const result = await scriptsApi.actionByAlias(alias);
    refreshingIndicators.value = new Set(
      Array.from(refreshingIndicators.value).filter((a) => a !== alias)
    );
    if (result.ok) {
      const script = result.data?.data?.script;
      if (script) {
        const idx = actions.value.findIndex((s) => s.alias === alias);
        if (idx !== -1) {
          actions.value[idx] = script;
        }
      }
    }
    return result;
  }

  async function refreshIndicators(aliases) {
    const chunkSize = 5;
    for (let i = 0; i < aliases.length; i += chunkSize) {
      const chunk = aliases.slice(i, i + chunkSize);
      await Promise.all(chunk.map((alias) => refreshAction(alias)));
    }
  }

  async function loadRegular() {
    return regularRequest.execute(async (signal) => {
      const result = await scriptsApi.regularList({ signal });
      if (result.ok) {
        regular.value = result.data?.data?.scripts || [];
      }
      return result;
    });
  }

  async function loadScopes() {
    return scopesRequest.execute(async (signal) => {
      const result = await scriptsApi.scopesList({ signal });
      if (result.ok) {
        scopes.value = result.data?.data?.scopes || [];
      }
      return result;
    });
  }

  async function runScript(alias, params = {}) {
    runningAliases.value = new Set(runningAliases.value).add(alias);
    lastRunResult.value = null;

    const result = await scriptsApi.runAction(alias, params);

    const next = new Set(runningAliases.value);
    next.delete(alias);
    runningAliases.value = next;

    if (!result.ok) {
      lastRunResult.value = { alias, ok: false, error: result.error };
      return result;
    }

    lastRunResult.value = {
      alias,
      ok: true,
      data: result.data?.data?.return?.result,
      execTime: result.data?.data?.return?.exec_time,
    };
    return result;
  }

  async function setActionState(alias, enabled) {
    const result = await scriptsApi.setActionState(alias, enabled);

    if (result.ok) {
      const idx = actions.value.findIndex((s) => s.alias === alias);
      if (idx !== -1) {
        actions.value[idx] = { ...actions.value[idx], state: enabled ? "enabled" : "disabled" };
      }
    }

    return result;
  }

  async function setRegularState(alias, enabled) {
    const result = await scriptsApi.setRegularState(alias, enabled);

    if (result.ok) {
      const idx = regular.value.findIndex((s) => s.alias === alias);
      if (idx !== -1) {
        regular.value[idx] = { ...regular.value[idx], state: enabled ? "enabled" : "disabled" };
      }
    }

    return result;
  }

  async function setScopeState(name, enabled) {
    const result = await scriptsApi.setScopeState(name, enabled);

    if (result.ok) {
      const idx = scopes.value.findIndex((s) => s.name === name);
      if (idx !== -1) {
        scopes.value[idx] = { ...scopes.value[idx], state: enabled ? "enabled" : "disabled" };
      }
    }

    return result;
  }

  async function assignToArea(scriptId, areaId) {
    const result = await scriptsApi.placeInArea({ target_id: scriptId, place_in_area_id: areaId });
    if (result.ok) {
      const actionIdx = actions.value.findIndex((s) => s.id === scriptId);
      if (actionIdx !== -1) {
        actions.value.splice(actionIdx, 1, { ...actions.value[actionIdx], area_id: areaId });
      }
      const regularIdx = regular.value.findIndex((s) => s.id === scriptId);
      if (regularIdx !== -1) {
        regular.value.splice(regularIdx, 1, { ...regular.value[regularIdx], area_id: areaId });
      }
    }
    return result;
  }

  async function unassignFromArea(scriptId) {
    const result = await scriptsApi.unassign(scriptId);
    if (result.ok) {
      const actionIdx = actions.value.findIndex((s) => s.id === scriptId);
      if (actionIdx !== -1) {
        actions.value.splice(actionIdx, 1, { ...actions.value[actionIdx], area_id: null });
      }
      const regularIdx = regular.value.findIndex((s) => s.id === scriptId);
      if (regularIdx !== -1) {
        regular.value.splice(regularIdx, 1, { ...regular.value[regularIdx], area_id: null });
      }
    }
    return result;
  }

  async function loadScopeCode(name) {
    return scopeCodeRequest.execute(async (signal) => {
      const result = await scriptsApi.scopeCode(name, { signal });
      if (result.ok) {
        currentScopeCode.value = typeof result.data === "string" ? result.data : "";
      }
      return result;
    });
  }

  function clearScopeCode() {
    currentScopeCode.value = "";
    scopeCodeRequest.clear();
  }

  return {
    actions,
    regular,
    scopes,
    isLoadingActions: actionsRequest.isLoading,
    isLoadingRegular: regularRequest.isLoading,
    isLoadingScopes: scopesRequest.isLoading,
    errorActions: actionsRequest.error,
    errorRegular: regularRequest.error,
    errorScopes: scopesRequest.error,
    runningAliases,
    lastRunResult,
    currentScopeCode,
    isLoadingScopeCode: scopeCodeRequest.isLoading,
    errorScopeCode: scopeCodeRequest.error,
    totalActions,
    totalRegular,
    totalScopes,
    isRunning,
    isRefreshingIndicator,
    actionByAlias,
    regularByAlias,
    scopeByName,
    actionsByScope,
    regularByScope,
    loadActions,
    loadRegular,
    loadScopes,
    runScript,
    refreshAction,
    refreshIndicators,
    setActionState,
    setRegularState,
    setScopeState,
    assignToArea,
    unassignFromArea,
    loadScopeCode,
    clearScopeCode,
  };
});
