import { axiosBaseQuery } from '@/api/baseQuery';
import type { InputItem } from '@/components/Build/components/ModuleInputForm';
import { PROJECTS_URL } from '@/components/Build/store/api';
import type { AddedModule, Project, ProjectListResponse } from '@/components/Build/types';
import type { CmdbItem, CmdbSubEntry } from '@/components/Cmdb/store/cmdbSlice/thunks';
import { CMDB_ITEM_TYPES } from '@/components/Cmdb/store/itemTypes';
import { formEncoded, notifyResult } from '@/utils/api';
import { createApi } from '@reduxjs/toolkit/query/react';

export const GROUP_DATA_URL = '/groups_app/SharedGroupsCmdb';

const GROUP_DATA_PAGE_SIZE = 100;

interface ModuleInput {
  input_spec?: InputItem[];
}

interface ModuleInputArgs {
  encodedName: boolean;
  moduleName: string;
  projectId: number;
}

interface ModuleInputRenderArgs {
  input: InputItem[];
  moduleName: string;
  projectId: number;
}

interface AugmentVariable {
  comment?: string;
  value: unknown;
}

export interface Augment {
  variables?: Record<string, AugmentVariable>;
}

interface RenderedModuleInput {
  augment: Augment;
  status?: string;
}

interface ModuleInputMeta {
  input: InputItem[];
  moduleName: string;
  projectId: number;
}

export interface ModuleInputEntry extends Omit<CmdbItem, 'entries' | 'hostkey' | 'meta'> {
  entries: Omit<CmdbSubEntry, 'hostkey'>[];
  meta: ModuleInputMeta;
}

interface GroupDataListResponse {
  data: ModuleInputEntry[];
}

interface SaveModuleInputArgs extends ModuleInputMeta {
  augment: Augment;
  entryId?: number;
  groupId: string;
}

export const groupModulesApi = createApi({
  reducerPath: 'groupModulesApi',
  baseQuery: axiosBaseQuery(),
  // Build app and the group Data tab write the same records from their own stores,
  // so a cached entry can be stale, always refetch on mount.
  refetchOnMountOrArgChange: true,
  tagTypes: ['ProjectModules', 'GroupModuleInput'],
  endpoints: builder => ({
    getDeployedProject: builder.query<Project | null, void>({
      query: () => ({ url: `${PROJECTS_URL}/list`, params: { limit: 1, is_deployed_locally: true } }),
      transformResponse: (response: ProjectListResponse) => response.data[0] ?? null
    }),
    getProjectModules: builder.query<AddedModule[], number>({
      query: projectId => ({ url: `${PROJECTS_URL}/modules/${projectId}` }),
      providesTags: ['ProjectModules']
    }),
    getProjectModulesInput: builder.query<ModuleInput, ModuleInputArgs>({
      query: ({ projectId, moduleName, encodedName }) => ({
        url: `${PROJECTS_URL}/module_input/${projectId}/${moduleName}/`,
        params: { encodedName: encodedName ? 'true' : 'false' }
      })
    }),
    renderModuleInput: builder.mutation<RenderedModuleInput, ModuleInputRenderArgs>({
      query: ({ projectId, moduleName, input }) => ({
        url: `${PROJECTS_URL}/module_input_render/${projectId}/${moduleName}/`,
        method: 'post',
        data: { input }
      }),
      onQueryStarted: notifyResult('Failed to render the module input data.')
    }),
    getGroupModuleInputs: builder.query<ModuleInputEntry[], string>({
      query: groupId => ({ url: `${GROUP_DATA_URL}/items/${groupId}`, params: { page: 1, perPage: GROUP_DATA_PAGE_SIZE } }),
      transformResponse: (response: GroupDataListResponse) => response.data.filter(entry => !!entry.meta?.moduleName),
      providesTags: ['GroupModuleInput']
    }),
    saveModuleInput: builder.mutation<void, SaveModuleInputArgs>({
      query: ({ augment, entryId, groupId, input, moduleName, projectId }) => ({
        url: entryId ? `${GROUP_DATA_URL}/item/${entryId}/` : `${GROUP_DATA_URL}/item/${groupId}`,
        method: entryId ? 'put' : 'post',
        headers: formEncoded.headers,
        data: new URLSearchParams({
          data: JSON.stringify({
            name: moduleName,
            description: `Input data for the ${moduleName} module`,
            type: CMDB_ITEM_TYPES.VARIABLE,
            meta: { input, moduleName, projectId },
            entries: Object.entries(augment.variables ?? {}).map(([name, variable]) => ({
              item_name: name,
              item_type: CMDB_ITEM_TYPES.VARIABLE,
              item_value: variable.value
            }))
          })
        }).toString()
      }),
      onQueryStarted: notifyResult('Failed to save the module input data.', 'Module input data saved.'),
      invalidatesTags: ['GroupModuleInput']
    })
  })
});

export const {
  useGetDeployedProjectQuery,
  useGetGroupModuleInputsQuery,
  useGetProjectModulesQuery,
  useGetProjectModulesInputQuery,
  useRenderModuleInputMutation,
  useSaveModuleInputMutation
} = groupModulesApi;
