import Api from '@northern.tech/store/api/general-api';

import type {
  AddedModule,
  Module,
  ModulesListResponse,
  Project,
  ProjectListResponse,
  SshKey,
  VcsSyncStatus
} from '../types';

const PROJECTS_URL = '/build_app/projects';
const MODULES_URL = '/build_app/build_modules/modules';
const MODULE_URL = '/build_app/build_modules/module';
const SSH_KEY_URL = '/sshKey/key';
const CMDB_URL = '/cmdb';
const HUB_INFO_URL = '/hub_management/api/hubInfo';
const AGENT_RUN_URL = '/actions/agent_run';

const formEncoded = { headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' } };

// ===== Projects =====

export const listProjects = (limit = 10) =>
  Api.get<ProjectListResponse>(`${PROJECTS_URL}/list`, { params: { limit } }).then(r => r.data);

export const getProject = (id: number | string) =>
  Api.get<Project>(`${PROJECTS_URL}/project/${id}`).then(r => r.data);

export const createProject = (project: unknown) =>
  Api.post<Project>(`${PROJECTS_URL}/project`, project).then(r => r.data);

export const createLocalProject = (masterfiles: string) =>
  Api.post<Project>(`${PROJECTS_URL}/local_project`, { masterfiles }).then(r => r.data);

export const updateProject = (id: number | string, project: unknown) =>
  Api.put<Project>(`${PROJECTS_URL}/project/${id}`, project).then(r => r.data);

export const deleteProject = (id: number | string) =>
  Api.delete(`${PROJECTS_URL}/project/${id}`);

export const getProjectModules = (id: number | string) =>
  Api.get<AddedModule[]>(`${PROJECTS_URL}/modules/${id}`).then(r => r.data);

export const vcsSynchronized = (id: number | string) =>
  Api.get<VcsSyncStatus>(`${PROJECTS_URL}/vcsSynchronized/${id}`).then(r => r.data);

export const anyProjectDeployed = () =>
  Api.get<{ deployed: boolean }>(`${PROJECTS_URL}/anyProjectDeployed`).then(r => r.data);

export const synchronizeVcs = (id: number | string, localDeploy: boolean) =>
  Api.post(`${PROJECTS_URL}/synchronize/${id}`, {}, { params: { localDeploy: localDeploy ? 'true' : 'false' } });

export const pushProject = (id: number | string) => Api.post(`${PROJECTS_URL}/push/${id}`, {});
export const localDeployProject = (id: number | string) => Api.post(`${PROJECTS_URL}/localDeploy/${id}`, {});
export const refreshProject = (id: number | string) =>
  Api.post<{ status: string }>(`${PROJECTS_URL}/refresh/${id}`, {}).then(r => r.data);
export const rebaseProject = (id: number | string) => Api.post(`${PROJECTS_URL}/rebase/${id}`, {});
export const forcePullProject = (id: number | string) => Api.post(`${PROJECTS_URL}/forcePull/${id}`, {});
export const forceRebaseProject = (id: number | string) => Api.post(`${PROJECTS_URL}/forceRebase/${id}`, {});
export const setDefaultAction = (id: number | string, action: string) =>
  Api.post(`${PROJECTS_URL}/defaultAction/${id}`, { action });

export const addModule = (projectId: number | string, name: string, version: string) =>
  Api.post(`${PROJECTS_URL}/module/${projectId}/${name}/${version}`, {});
export const addModuleByUrl = (projectId: number | string, url: string) =>
  Api.post(`${PROJECTS_URL}/module_by_url/${projectId}`, { url });
// `gitMessage` becomes the commit message for the update; the API falls back to its
// own default when it is omitted.
export const updateModuleVersion = (projectId: number | string, name: string, version: string, gitMessage?: string) =>
  Api.put(`${PROJECTS_URL}/module/${projectId}/${name}/${version}`, gitMessage ? { gitMessage } : {});
export const removeProjectModule = (projectId: number | string, name: string, encodedName = false) =>
  Api.delete(`${PROJECTS_URL}/module/${projectId}/${name}/`, { params: { encodedName: encodedName ? 'true' : 'false' } });
export const getModuleInput = (projectId: number | string, name: string, encodedName = false) =>
  Api.get(`${PROJECTS_URL}/module_input/${projectId}/${name}/`, { params: { encodedName: encodedName ? 'true' : 'false' } }).then(r => r.data);
export const setModuleInput = (projectId: number | string, name: string, input: unknown, encodedName = false) =>
  Api.post(`${PROJECTS_URL}/module_input/${projectId}/${name}/`, { input }, { params: { encodedName: encodedName ? 'true' : 'false' } });

// ===== Modules index =====

export const listModules = (params: Record<string, string | number>) =>
  Api.get<ModulesListResponse>(MODULES_URL, { params }).then(r => r.data);
export const refreshModulesList = () => Api.post(MODULES_URL, {});
export const getModule = (name: string, version?: string | null) =>
  Api.get<Module>(version ? `${MODULE_URL}/${name}/${version}` : `${MODULE_URL}/${name}`).then(r => r.data);

// ===== SSH keys =====

export const generateSshKey = () => Api.post<SshKey>(SSH_KEY_URL, {}).then(r => r.data);
export const getSshKey = (id: number | string) => Api.get<SshKey>(`${SSH_KEY_URL}/${id}`).then(r => r.data);
export const deleteSshKey = (id: number | string) => Api.delete(`${SSH_KEY_URL}/${id}`);

// ===== Hub / CMDB / actions (deployment plumbing) =====

export const getHubInfo = () =>
  Api.get<{ hostkey?: string; release?: { isAlpha: boolean; version: string } }>(HUB_INFO_URL).then(r => r.data);

interface CmdbEntry {
  description: string;
  name: string;
  type: string;
}

export const CMDB_UPDATE_POLICY = {
  type: 'class',
  name: 'default:cfengine_internal_masterfiles_update',
  description: 'Update default policy distribution point from upstream repository. Created by Build application.'
};

export const getCmdbItem = async (identifier: string) => {
  try {
    const { data } = await Api.get(`${CMDB_URL}/item/${identifier}/${CMDB_UPDATE_POLICY.type}/${CMDB_UPDATE_POLICY.name}/`);
    return data;
  } catch {
    return undefined;
  }
};

export const createCmdbItem = (identifier: string, entry: CmdbEntry) => {
  const body = new URLSearchParams();
  body.set(
    'data',
    JSON.stringify({
      ...entry,
      tags: [],
      meta: {},
      entries: [{ item_name: entry.name, item_value: null, item_type: entry.type }]
    })
  );
  return Api.post(`${CMDB_URL}/item/${identifier}/`, body.toString(), formEncoded);
};

export const deleteCmdbItem = (entryId: string) => Api.delete(`${CMDB_URL}/item/${entryId}/`);

export const agentRun = (hostkey: string) =>
  Api.post(AGENT_RUN_URL, new URLSearchParams({ hostkey }).toString(), formEncoded);

export const clearVcs = () => Api.post('/settingsApi/clearVCS', {});
