import * as plugins from './plugins.js';
import * as interfaces from '../ts_interfaces/index.js';

// ============================================================================
// Smartstate instance
// ============================================================================
export const appState = new plugins.domtools.plugins.smartstate.Smartstate();

// ============================================================================
// State Part Interfaces
// ============================================================================

export interface ILoginState {
  identity: interfaces.data.IIdentity | null;
  isLoggedIn: boolean;
}

export interface IConnectionsState {
  connections: interfaces.data.IProviderConnection[];
  activeConnectionId: string | null;
}

export interface IDataState {
  projects: interfaces.data.IProject[];
  groups: interfaces.data.IGroup[];
  secrets: interfaces.data.ISecret[];
  pipelines: interfaces.data.IPipeline[];
  pipelineJobs: interfaces.data.IPipelineJob[];
  currentJobLog: string;
}

export interface IActionLogState {
  entries: interfaces.data.IActionLogEntry[];
  total: number;
}

export interface INavigationContext {
  connectionId?: string;
  scope?: 'project' | 'group';
  scopeId?: string;
  projectId?: string;
}

export interface IUiState {
  activeView: string;
  autoRefresh: boolean;
  refreshInterval: number;
  navigationContext?: INavigationContext;
}

// ============================================================================
// State Parts
// ============================================================================

export const loginStatePart = await appState.getStatePart<ILoginState>(
  'login',
  {
    identity: null,
    isLoggedIn: false,
  },
  'persistent',
);

export const connectionsStatePart = await appState.getStatePart<IConnectionsState>(
  'connections',
  {
    connections: [],
    activeConnectionId: null,
  },
  'soft',
);

export const dataStatePart = await appState.getStatePart<IDataState>(
  'data',
  {
    projects: [],
    groups: [],
    secrets: [],
    pipelines: [],
    pipelineJobs: [],
    currentJobLog: '',
  },
  'soft',
);

export const actionLogStatePart = await appState.getStatePart<IActionLogState>(
  'actionLog',
  {
    entries: [],
    total: 0,
  },
  'soft',
);

export const uiStatePart = await appState.getStatePart<IUiState>(
  'ui',
  {
    activeView: 'overview',
    autoRefresh: true,
    refreshInterval: 30000,
  },
);

// ============================================================================
// Helpers
// ============================================================================

interface IActionContext {
  identity: interfaces.data.IIdentity | null;
}

const getActionContext = (): IActionContext => {
  return { identity: loginStatePart.getState().identity };
};

// ============================================================================
// Login Actions
// ============================================================================

export const loginAction = loginStatePart.createAction<{
  username: string;
  password: string;
}>(async (statePartArg, dataArg) => {
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_AdminLogin
    >('/typedrequest', 'adminLogin');

    const response = await typedRequest.fire({
      username: dataArg.username,
      password: dataArg.password,
    });

    return {
      identity: response.identity || null,
      isLoggedIn: !!response.identity,
    };
  } catch (err) {
    console.error('Login failed:', err);
    return { identity: null, isLoggedIn: false };
  }
});

export const logoutAction = loginStatePart.createAction(async (_statePartArg) => {
  const context = getActionContext();
  try {
    if (context.identity) {
      const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
        interfaces.requests.IReq_AdminLogout
      >('/typedrequest', 'adminLogout');
      await typedRequest.fire({ identity: context.identity });
    }
  } catch (err) {
    console.error('Logout error:', err);
  }
  return { identity: null, isLoggedIn: false };
});

// ============================================================================
// Connections Actions
// ============================================================================

export const fetchConnectionsAction = connectionsStatePart.createAction(async (statePartArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetConnections
    >('/typedrequest', 'getConnections');
    const response = await typedRequest.fire({ identity: context.identity! });
    return { ...statePartArg.getState(), connections: response.connections };
  } catch (err) {
    console.error('Failed to fetch connections:', err);
    return statePartArg.getState();
  }
});

export const createConnectionAction = connectionsStatePart.createAction<{
  name: string;
  providerType: interfaces.data.TProviderType;
  baseUrl: string;
  token: string;
  groupFilter?: string;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_CreateConnection
    >('/typedrequest', 'createConnection');
    await typedRequest.fire({
      identity: context.identity!,
      ...dataArg,
    });
    // Re-fetch
    const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetConnections
    >('/typedrequest', 'getConnections');
    const listResp = await listReq.fire({ identity: context.identity! });
    return { ...statePartArg.getState(), connections: listResp.connections };
  } catch (err) {
    console.error('Failed to create connection:', err);
    return statePartArg.getState();
  }
});

export const testConnectionAction = connectionsStatePart.createAction<{
  connectionId: string;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_TestConnection
    >('/typedrequest', 'testConnection');
    const result = await typedRequest.fire({
      identity: context.identity!,
      connectionId: dataArg.connectionId,
    });
    // Re-fetch to get updated status
    const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetConnections
    >('/typedrequest', 'getConnections');
    const listResp = await listReq.fire({ identity: context.identity! });
    return { ...statePartArg.getState(), connections: listResp.connections };
  } catch (err) {
    console.error('Failed to test connection:', err);
    return statePartArg.getState();
  }
});

export const deleteConnectionAction = connectionsStatePart.createAction<{
  connectionId: string;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_DeleteConnection
    >('/typedrequest', 'deleteConnection');
    await typedRequest.fire({
      identity: context.identity!,
      connectionId: dataArg.connectionId,
    });
    const state = statePartArg.getState();
    return {
      ...state,
      connections: state.connections.filter((c) => c.id !== dataArg.connectionId),
      activeConnectionId: state.activeConnectionId === dataArg.connectionId ? null : state.activeConnectionId,
    };
  } catch (err) {
    console.error('Failed to delete connection:', err);
    return statePartArg.getState();
  }
});

export const pauseConnectionAction = connectionsStatePart.createAction<{
  connectionId: string;
  paused: boolean;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_PauseConnection
    >('/typedrequest', 'pauseConnection');
    await typedRequest.fire({
      identity: context.identity!,
      ...dataArg,
    });
    // Re-fetch to get updated status
    const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetConnections
    >('/typedrequest', 'getConnections');
    const listResp = await listReq.fire({ identity: context.identity! });
    return { ...statePartArg.getState(), connections: listResp.connections };
  } catch (err) {
    console.error('Failed to pause/resume connection:', err);
    return statePartArg.getState();
  }
});

export const updateConnectionAction = connectionsStatePart.createAction<{
  connectionId: string;
  name?: string;
  baseUrl?: string;
  token?: string;
  groupFilter?: string;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_UpdateConnection
    >('/typedrequest', 'updateConnection');
    await typedRequest.fire({
      identity: context.identity!,
      ...dataArg,
    });
    // Re-fetch to get updated data
    const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetConnections
    >('/typedrequest', 'getConnections');
    const listResp = await listReq.fire({ identity: context.identity! });
    return { ...statePartArg.getState(), connections: listResp.connections };
  } catch (err) {
    console.error('Failed to update connection:', err);
    return statePartArg.getState();
  }
});

// ============================================================================
// Projects Actions
// ============================================================================

export const fetchProjectsAction = dataStatePart.createAction<{
  connectionId: string;
  search?: string;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetProjects
    >('/typedrequest', 'getProjects');
    const response = await typedRequest.fire({
      identity: context.identity!,
      connectionId: dataArg.connectionId,
      search: dataArg.search,
    });
    return { ...statePartArg.getState(), projects: response.projects };
  } catch (err) {
    console.error('Failed to fetch projects:', err);
    return statePartArg.getState();
  }
});

// ============================================================================
// Groups Actions
// ============================================================================

export const fetchGroupsAction = dataStatePart.createAction<{
  connectionId: string;
  search?: string;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetGroups
    >('/typedrequest', 'getGroups');
    const response = await typedRequest.fire({
      identity: context.identity!,
      connectionId: dataArg.connectionId,
      search: dataArg.search,
    });
    return { ...statePartArg.getState(), groups: response.groups };
  } catch (err) {
    console.error('Failed to fetch groups:', err);
    return statePartArg.getState();
  }
});

// ============================================================================
// Secrets Actions
// ============================================================================

export const fetchSecretsAction = dataStatePart.createAction<{
  connectionId: string;
  scope: 'project' | 'group';
  scopeId: string;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetSecrets
    >('/typedrequest', 'getSecrets');
    const response = await typedRequest.fire({
      identity: context.identity!,
      connectionId: dataArg.connectionId,
      scope: dataArg.scope,
      scopeId: dataArg.scopeId,
    });
    return { ...statePartArg.getState(), secrets: response.secrets };
  } catch (err) {
    console.error('Failed to fetch secrets:', err);
    return statePartArg.getState();
  }
});

export const fetchAllSecretsAction = dataStatePart.createAction<{
  connectionId: string;
  scope?: 'project' | 'group';
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    // When no scope specified, fetch both project and group secrets in parallel
    const scopes: Array<'project' | 'group'> = dataArg.scope ? [dataArg.scope] : ['project', 'group'];
    const results = await Promise.all(
      scopes.map(async (scope) => {
        const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
          interfaces.requests.IReq_GetAllSecrets
        >('/typedrequest', 'getAllSecrets');
        const response = await typedRequest.fire({
          identity: context.identity!,
          connectionId: dataArg.connectionId,
          scope,
        });
        return response.secrets;
      }),
    );
    return { ...statePartArg.getState(), secrets: results.flat() };
  } catch (err) {
    console.error('Failed to fetch all secrets:', err);
    return statePartArg.getState();
  }
});

export const createSecretAction = dataStatePart.createAction<{
  connectionId: string;
  scope: 'project' | 'group';
  scopeId: string;
  key: string;
  value: string;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_CreateSecret
    >('/typedrequest', 'createSecret');
    await typedRequest.fire({
      identity: context.identity!,
      ...dataArg,
    });
    // Re-fetch only the affected entity's secrets and merge
    const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetSecrets
    >('/typedrequest', 'getSecrets');
    const listResp = await listReq.fire({
      identity: context.identity!,
      connectionId: dataArg.connectionId,
      scope: dataArg.scope,
      scopeId: dataArg.scopeId,
    });
    const state = statePartArg.getState();
    const otherSecrets = state.secrets.filter(
      (s) => !(s.scopeId === dataArg.scopeId && s.scope === dataArg.scope),
    );
    return { ...state, secrets: [...otherSecrets, ...listResp.secrets] };
  } catch (err) {
    console.error('Failed to create secret:', err);
    return statePartArg.getState();
  }
});

export const updateSecretAction = dataStatePart.createAction<{
  connectionId: string;
  scope: 'project' | 'group';
  scopeId: string;
  key: string;
  value: string;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_UpdateSecret
    >('/typedrequest', 'updateSecret');
    await typedRequest.fire({
      identity: context.identity!,
      ...dataArg,
    });
    // Re-fetch only the affected entity's secrets and merge
    const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetSecrets
    >('/typedrequest', 'getSecrets');
    const listResp = await listReq.fire({
      identity: context.identity!,
      connectionId: dataArg.connectionId,
      scope: dataArg.scope,
      scopeId: dataArg.scopeId,
    });
    const state = statePartArg.getState();
    const otherSecrets = state.secrets.filter(
      (s) => !(s.scopeId === dataArg.scopeId && s.scope === dataArg.scope),
    );
    return { ...state, secrets: [...otherSecrets, ...listResp.secrets] };
  } catch (err) {
    console.error('Failed to update secret:', err);
    return statePartArg.getState();
  }
});

export const deleteSecretAction = dataStatePart.createAction<{
  connectionId: string;
  scope: 'project' | 'group';
  scopeId: string;
  key: string;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_DeleteSecret
    >('/typedrequest', 'deleteSecret');
    await typedRequest.fire({
      identity: context.identity!,
      ...dataArg,
    });
    const state = statePartArg.getState();
    return {
      ...state,
      secrets: state.secrets.filter(
        (s) => !(s.key === dataArg.key && s.scopeId === dataArg.scopeId && s.scope === dataArg.scope),
      ),
    };
  } catch (err) {
    console.error('Failed to delete secret:', err);
    return statePartArg.getState();
  }
});

// ============================================================================
// Pipelines Actions
// ============================================================================

export const fetchPipelinesAction = dataStatePart.createAction<{
  connectionId: string;
  projectId?: string;
  viewMode?: 'current' | 'project' | 'group' | 'error';
  groupId?: string;
  status?: string;
  sortBy?: 'created' | 'duration' | 'status';
  timeRange?: '1h' | '6h' | '1d' | '3d' | '7d' | '30d';
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetPipelines
    >('/typedrequest', 'getPipelines');
    const response = await typedRequest.fire({
      identity: context.identity!,
      connectionId: dataArg.connectionId,
      projectId: dataArg.projectId,
      viewMode: dataArg.viewMode,
      groupId: dataArg.groupId,
      status: dataArg.status,
      sortBy: dataArg.sortBy,
      timeRange: dataArg.timeRange,
    });
    return { ...statePartArg.getState(), pipelines: response.pipelines };
  } catch (err) {
    console.error('Failed to fetch pipelines:', err);
    return statePartArg.getState();
  }
});

export const fetchPipelineJobsAction = dataStatePart.createAction<{
  connectionId: string;
  projectId: string;
  pipelineId: string;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetPipelineJobs
    >('/typedrequest', 'getPipelineJobs');
    const response = await typedRequest.fire({
      identity: context.identity!,
      connectionId: dataArg.connectionId,
      projectId: dataArg.projectId,
      pipelineId: dataArg.pipelineId,
    });
    return { ...statePartArg.getState(), pipelineJobs: response.jobs };
  } catch (err) {
    console.error('Failed to fetch pipeline jobs:', err);
    return statePartArg.getState();
  }
});

export const retryPipelineAction = dataStatePart.createAction<{
  connectionId: string;
  projectId: string;
  pipelineId: string;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_RetryPipeline
    >('/typedrequest', 'retryPipeline');
    await typedRequest.fire({
      identity: context.identity!,
      ...dataArg,
    });
    // Re-fetch pipelines
    const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetPipelines
    >('/typedrequest', 'getPipelines');
    const listResp = await listReq.fire({
      identity: context.identity!,
      connectionId: dataArg.connectionId,
      projectId: dataArg.projectId,
    });
    return { ...statePartArg.getState(), pipelines: listResp.pipelines };
  } catch (err) {
    console.error('Failed to retry pipeline:', err);
    return statePartArg.getState();
  }
});

export const cancelPipelineAction = dataStatePart.createAction<{
  connectionId: string;
  projectId: string;
  pipelineId: string;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_CancelPipeline
    >('/typedrequest', 'cancelPipeline');
    await typedRequest.fire({
      identity: context.identity!,
      ...dataArg,
    });
    // Re-fetch pipelines
    const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetPipelines
    >('/typedrequest', 'getPipelines');
    const listResp = await listReq.fire({
      identity: context.identity!,
      connectionId: dataArg.connectionId,
      projectId: dataArg.projectId,
    });
    return { ...statePartArg.getState(), pipelines: listResp.pipelines };
  } catch (err) {
    console.error('Failed to cancel pipeline:', err);
    return statePartArg.getState();
  }
});

// ============================================================================
// Logs Actions
// ============================================================================

export const fetchJobLogAction = dataStatePart.createAction<{
  connectionId: string;
  projectId: string;
  jobId: string;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetJobLog
    >('/typedrequest', 'getJobLog');
    const response = await typedRequest.fire({
      identity: context.identity!,
      ...dataArg,
    });
    return { ...statePartArg.getState(), currentJobLog: response.log };
  } catch (err) {
    console.error('Failed to fetch job log:', err);
    return statePartArg.getState();
  }
});

// ============================================================================
// Action Log Actions
// ============================================================================

export const fetchActionLogAction = actionLogStatePart.createAction<{
  limit?: number;
  offset?: number;
  entityType?: interfaces.data.TActionEntity;
} | null>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetActionLog
    >('/typedrequest', 'getActionLog');
    const response = await typedRequest.fire({
      identity: context.identity!,
      limit: dataArg?.limit,
      offset: dataArg?.offset,
      entityType: dataArg?.entityType,
    });
    return { entries: response.entries, total: response.total };
  } catch (err) {
    console.error('Failed to fetch action log:', err);
    return statePartArg.getState();
  }
});

// ============================================================================
// UI Actions
// ============================================================================

export const setActiveViewAction = uiStatePart.createAction<{
  view: string;
  navigationContext?: INavigationContext;
}>(
  async (statePartArg, dataArg) => {
    return {
      ...statePartArg.getState(),
      activeView: dataArg.view,
      navigationContext: dataArg.navigationContext,
    };
  },
);

export const clearNavigationContextAction = uiStatePart.createAction(
  async (statePartArg) => {
    return { ...statePartArg.getState(), navigationContext: undefined };
  },
);

export const toggleAutoRefreshAction = uiStatePart.createAction(async (statePartArg) => {
  const state = statePartArg.getState();
  return { ...state, autoRefresh: !state.autoRefresh };
});

export const setRefreshIntervalAction = uiStatePart.createAction<{ interval: number }>(
  async (statePartArg, dataArg) => {
    return { ...statePartArg.getState(), refreshInterval: dataArg.interval };
  },
);

// ============================================================================
// Managed Secrets State
// ============================================================================

export interface IManagedSecretsState {
  managedSecrets: interfaces.data.IManagedSecret[];
}

export const managedSecretsStatePart = await appState.getStatePart<IManagedSecretsState>(
  'managedSecrets',
  { managedSecrets: [] },
  'soft',
);

export const fetchManagedSecretsAction = managedSecretsStatePart.createAction(
  async (statePartArg) => {
    const context = getActionContext();
    try {
      const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
        interfaces.requests.IReq_GetManagedSecrets
      >('/typedrequest', 'getManagedSecrets');
      const response = await typedRequest.fire({ identity: context.identity! });
      return { managedSecrets: response.managedSecrets };
    } catch (err) {
      console.error('Failed to fetch managed secrets:', err);
      return statePartArg.getState();
    }
  },
);

export const createManagedSecretAction = managedSecretsStatePart.createAction<{
  key: string;
  value: string;
  description?: string;
  targets: interfaces.data.IManagedSecretTarget[];
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_CreateManagedSecret
    >('/typedrequest', 'createManagedSecret');
    await typedRequest.fire({ identity: context.identity!, ...dataArg });
    // Re-fetch
    const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetManagedSecrets
    >('/typedrequest', 'getManagedSecrets');
    const listResp = await listReq.fire({ identity: context.identity! });
    return { managedSecrets: listResp.managedSecrets };
  } catch (err) {
    console.error('Failed to create managed secret:', err);
    return statePartArg.getState();
  }
});

export const updateManagedSecretAction = managedSecretsStatePart.createAction<{
  managedSecretId: string;
  value?: string;
  description?: string;
  targets?: interfaces.data.IManagedSecretTarget[];
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_UpdateManagedSecret
    >('/typedrequest', 'updateManagedSecret');
    await typedRequest.fire({ identity: context.identity!, ...dataArg });
    const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetManagedSecrets
    >('/typedrequest', 'getManagedSecrets');
    const listResp = await listReq.fire({ identity: context.identity! });
    return { managedSecrets: listResp.managedSecrets };
  } catch (err) {
    console.error('Failed to update managed secret:', err);
    return statePartArg.getState();
  }
});

export const deleteManagedSecretAction = managedSecretsStatePart.createAction<{
  managedSecretId: string;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_DeleteManagedSecret
    >('/typedrequest', 'deleteManagedSecret');
    await typedRequest.fire({ identity: context.identity!, ...dataArg });
    const state = statePartArg.getState();
    return {
      managedSecrets: state.managedSecrets.filter((s) => s.id !== dataArg.managedSecretId),
    };
  } catch (err) {
    console.error('Failed to delete managed secret:', err);
    return statePartArg.getState();
  }
});

export const pushManagedSecretAction = managedSecretsStatePart.createAction<{
  managedSecretId: string;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_PushManagedSecret
    >('/typedrequest', 'pushManagedSecret');
    await typedRequest.fire({ identity: context.identity!, ...dataArg });
    const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetManagedSecrets
    >('/typedrequest', 'getManagedSecrets');
    const listResp = await listReq.fire({ identity: context.identity! });
    return { managedSecrets: listResp.managedSecrets };
  } catch (err) {
    console.error('Failed to push managed secret:', err);
    return statePartArg.getState();
  }
});

export const pushAllManagedSecretsAction = managedSecretsStatePart.createAction(
  async (statePartArg) => {
    const context = getActionContext();
    try {
      const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
        interfaces.requests.IReq_PushAllManagedSecrets
      >('/typedrequest', 'pushAllManagedSecrets');
      await typedRequest.fire({ identity: context.identity! });
      const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
        interfaces.requests.IReq_GetManagedSecrets
      >('/typedrequest', 'getManagedSecrets');
      const listResp = await listReq.fire({ identity: context.identity! });
      return { managedSecrets: listResp.managedSecrets };
    } catch (err) {
      console.error('Failed to push all managed secrets:', err);
      return statePartArg.getState();
    }
  },
);

// ============================================================================
// Sync State
// ============================================================================

export interface ISyncState {
  configs: interfaces.data.ISyncConfig[];
  repoStatuses: interfaces.data.ISyncRepoStatus[];
}

export const syncStatePart = await appState.getStatePart<ISyncState>(
  'sync',
  { configs: [], repoStatuses: [] },
  'soft',
);

export const fetchSyncConfigsAction = syncStatePart.createAction(async (statePartArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetSyncConfigs
    >('/typedrequest', 'getSyncConfigs');
    const response = await typedRequest.fire({ identity: context.identity! });
    return { ...statePartArg.getState(), configs: response.configs };
  } catch (err) {
    console.error('Failed to fetch sync configs:', err);
    return statePartArg.getState();
  }
});

export const createSyncConfigAction = syncStatePart.createAction<{
  name: string;
  sourceConnectionId: string;
  targetConnectionId: string;
  targetGroupOffset?: string;
  intervalMinutes?: number;
  enforceDelete?: boolean;
  enforceGroupDelete?: boolean;
  addMirrorHint?: boolean;
  useGroupAvatarsForProjects?: boolean;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_CreateSyncConfig
    >('/typedrequest', 'createSyncConfig');
    await typedRequest.fire({ identity: context.identity!, ...dataArg });
    // Re-fetch
    const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetSyncConfigs
    >('/typedrequest', 'getSyncConfigs');
    const listResp = await listReq.fire({ identity: context.identity! });
    return { ...statePartArg.getState(), configs: listResp.configs };
  } catch (err) {
    console.error('Failed to create sync config:', err);
    return statePartArg.getState();
  }
});

export const updateSyncConfigAction = syncStatePart.createAction<{
  syncConfigId: string;
  name?: string;
  targetGroupOffset?: string;
  intervalMinutes?: number;
  enforceDelete?: boolean;
  enforceGroupDelete?: boolean;
  addMirrorHint?: boolean;
  useGroupAvatarsForProjects?: boolean;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_UpdateSyncConfig
    >('/typedrequest', 'updateSyncConfig');
    await typedRequest.fire({ identity: context.identity!, ...dataArg });
    const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetSyncConfigs
    >('/typedrequest', 'getSyncConfigs');
    const listResp = await listReq.fire({ identity: context.identity! });
    return { ...statePartArg.getState(), configs: listResp.configs };
  } catch (err) {
    console.error('Failed to update sync config:', err);
    return statePartArg.getState();
  }
});

export const deleteSyncConfigAction = syncStatePart.createAction<{
  syncConfigId: string;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_DeleteSyncConfig
    >('/typedrequest', 'deleteSyncConfig');
    await typedRequest.fire({ identity: context.identity!, ...dataArg });
    const state = statePartArg.getState();
    return { ...state, configs: state.configs.filter((c) => c.id !== dataArg.syncConfigId) };
  } catch (err) {
    console.error('Failed to delete sync config:', err);
    return statePartArg.getState();
  }
});

export const pauseSyncConfigAction = syncStatePart.createAction<{
  syncConfigId: string;
  paused: boolean;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_PauseSyncConfig
    >('/typedrequest', 'pauseSyncConfig');
    await typedRequest.fire({ identity: context.identity!, ...dataArg });
    const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetSyncConfigs
    >('/typedrequest', 'getSyncConfigs');
    const listResp = await listReq.fire({ identity: context.identity! });
    return { ...statePartArg.getState(), configs: listResp.configs };
  } catch (err) {
    console.error('Failed to pause/resume sync config:', err);
    return statePartArg.getState();
  }
});

export const triggerSyncAction = syncStatePart.createAction<{
  syncConfigId: string;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_TriggerSync
    >('/typedrequest', 'triggerSync');
    await typedRequest.fire({ identity: context.identity!, ...dataArg });
    return statePartArg.getState();
  } catch (err) {
    console.error('Failed to trigger sync:', err);
    return statePartArg.getState();
  }
});

export const fetchSyncRepoStatusesAction = syncStatePart.createAction<{
  syncConfigId: string;
}>(async (statePartArg, dataArg) => {
  const context = getActionContext();
  try {
    const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetSyncRepoStatuses
    >('/typedrequest', 'getSyncRepoStatuses');
    const response = await typedRequest.fire({ identity: context.identity!, ...dataArg });
    return { ...statePartArg.getState(), repoStatuses: response.statuses };
  } catch (err) {
    console.error('Failed to fetch sync repo statuses:', err);
    return statePartArg.getState();
  }
});

// ============================================================================
// Sync Log — TypedSocket client for server-push entries
// ============================================================================

export async function fetchSyncLogs(limit = 200): Promise<interfaces.data.ISyncLogEntry[]> {
  const identity = loginStatePart.getState().identity;
  if (!identity) throw new Error('Not logged in');
  const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
    interfaces.requests.IReq_GetSyncLogs
  >('/typedrequest', 'getSyncLogs');
  const response = await typedRequest.fire({ identity, limit });
  return response.logs;
}

let syncLogSocketInitialized = false;

/**
 * Create a TypedSocket client that handles server-push sync log entries.
 * Dispatches 'gitops-sync-log-entry' custom events on document.
 * Call once after login.
 */
export async function initSyncLogSocket(): Promise<void> {
  if (syncLogSocketInitialized) return;
  syncLogSocketInitialized = true;

  try {
    const typedrouter = new plugins.domtools.plugins.typedrequest.TypedRouter();

    typedrouter.addTypedHandler(
      new plugins.domtools.plugins.typedrequest.TypedHandler<interfaces.requests.IReq_PushSyncLog>(
        'pushSyncLog',
        async (dataArg) => {
          document.dispatchEvent(
            new CustomEvent('gitops-sync-log-entry', { detail: dataArg.entry }),
          );
          return {};
        },
      ),
    );

    const typedsocketClient = await plugins.typedsocket.TypedSocket.createClient(
      typedrouter,
      plugins.typedsocket.TypedSocket.useWindowLocationOriginUrl(),
      { autoReconnect: true },
    );
    await typedsocketClient.setTag('syncLogClient', {});
  } catch (err) {
    console.error('Failed to init sync log TypedSocket client:', err);
    syncLogSocketInitialized = false;
  }
}

// ============================================================================
// Preview Helper
// ============================================================================

export async function previewSync(syncConfigId: string): Promise<{
  mappings: Array<{ sourceFullPath: string; targetFullPath: string }>;
  deletions: string[];
  groupDeletions: string[];
}> {
  const identity = loginStatePart.getState().identity;
  if (!identity) throw new Error('Not logged in');
  const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
    interfaces.requests.IReq_PreviewSync
  >('/typedrequest', 'previewSync');
  const response = await typedRequest.fire({ identity, syncConfigId });
  return { mappings: response.mappings, deletions: response.deletions, groupDeletions: response.groupDeletions };
}
