import { defineStore } from "pinia";
import type {
  AnonymizedWorkflowExecution,
  DevWorkflowExecutionIn,
  WorkflowExecutionIn,
  WorkflowExecutionOut,
} from "@/client/workflow";
import {
  WorkflowExecutionService,
  WorkflowExecutionStatus,
  WorkflowService,
} from "@/client/workflow";
import { useAuthStore } from "@/stores/users";
import dayjs from "dayjs";
import { set, get } from "idb-keyval";

export const useWorkflowExecutionStore = defineStore({
  id: "workflow-executions",
  state: () =>
    ({
      executionMapping: {},
      anonymizedExecutions: [],
      parameters: {},
    }) as {
      executionMapping: Record<string, WorkflowExecutionOut>;
      anonymizedExecutions: AnonymizedWorkflowExecution[];
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      parameters: Record<string, Record<string, any>>;
    },
  getters: {
    executions(): WorkflowExecutionOut[] {
      return Object.values(this.executionMapping);
    },
  },
  actions: {
    fetchExecutionsForDevStatistics(
      onFinally?: () => void,
    ): Promise<AnonymizedWorkflowExecution[]> {
      if (this.anonymizedExecutions.length > 0) {
        onFinally?.();
      }
      const userStore = useAuthStore();
      return WorkflowService.workflowGetDeveloperWorkflowStatistics(
        userStore.currentUID,
      )
        .then((executions) => {
          this.anonymizedExecutions = executions;
          return executions;
        })
        .finally(onFinally);
    },
    fetchExecutions(onFinally?: () => void): Promise<WorkflowExecutionOut[]> {
      if (Object.keys(this.executionMapping).length > 0) {
        onFinally?.();
      }
      const userStore = useAuthStore();
      return WorkflowExecutionService.workflowExecutionListWorkflowExecutions(
        userStore.currentUID,
      )
        .then((executions) => {
          const newMapping: Record<string, WorkflowExecutionOut> = {};
          for (const execution of executions) {
            newMapping[execution.execution_id] = execution;
          }
          this.executionMapping = newMapping;
          return executions;
        })
        .finally(onFinally);
    },
    fetchExecution(
      executionId: string,
      onFinally?: () => void,
    ): Promise<WorkflowExecutionOut> {
      if (this.executionMapping[executionId] != undefined) {
        onFinally?.();
      }
      return WorkflowExecutionService.workflowExecutionGetWorkflowExecution(
        executionId,
      )
        .then((execution) => {
          this.executionMapping[execution.execution_id] = execution;
          return execution;
        })
        .finally(onFinally);
    },
    fetchExecutionParameters(
      executionId: string,
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
    ): Promise<Record<string, any>> {
      if (Object.keys(this.parameters).includes(executionId)) {
        return Promise.resolve(this.parameters[executionId]);
      }
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      return get<Record<string, any>>(executionId)
        .then((parameters) => {
          if (parameters != undefined) {
            return parameters;
          }
          return WorkflowExecutionService.workflowExecutionGetWorkflowExecutionParams(
            executionId,
          ).then((parameters) => {
            set(executionId, parameters);
            return parameters;
          });
        })
        .then((parameters) => {
          this.parameters[executionId] = parameters;
          return parameters;
        });
    },
    deleteExecution(executionId: string): Promise<void> {
      return WorkflowExecutionService.workflowExecutionDeleteWorkflowExecution(
        executionId,
      ).then(() => {
        delete this.executionMapping[executionId];
      });
    },
    cancelExecution(executionId: string): Promise<void> {
      return WorkflowExecutionService.workflowExecutionCancelWorkflowExecution(
        executionId,
      ).then(() => {
        if (this.executionMapping[executionId] == undefined) {
          this.fetchExecution(executionId);
        } else {
          this.executionMapping[executionId].status =
            WorkflowExecutionStatus.CANCELED;
          this.executionMapping[executionId].end_time = dayjs().unix();
        }
      });
    },
    startExecution(
      executionIn: WorkflowExecutionIn,
    ): Promise<WorkflowExecutionOut> {
      return WorkflowExecutionService.workflowExecutionStartWorkflow(
        executionIn,
      ).then((execution) => {
        this.executionMapping[execution.execution_id] = execution;
        return execution;
      });
    },
    startDevExecution(
      executionIn: DevWorkflowExecutionIn,
    ): Promise<WorkflowExecutionOut> {
      return WorkflowExecutionService.workflowExecutionStartArbitraryWorkflow(
        executionIn,
      ).then((execution) => {
        this.executionMapping[execution.execution_id] = execution;
        return execution;
      });
    },
  },
});