import * as plugins from '../plugins.js';
import * as interfaces from '../../ts_interfaces/index.js';
import { appState } from './shared.js';
import { getActionContext } from './login.js';

// ============================================================================
// Remote Ingress State
// ============================================================================

export interface IRemoteIngressState {
  edges: interfaces.data.IRemoteIngress[];
  statuses: interfaces.data.IRemoteIngressStatus[];
  hubSettings: interfaces.data.IRemoteIngressHubSettings | null;
  selectedEdgeId: string | null;
  newEdgeId: string | null;
  isLoading: boolean;
  error: string | null;
  lastUpdated: number;
}

export const remoteIngressStatePart = await appState.getStatePart<IRemoteIngressState>(
  'remoteIngress',
  {
    edges: [],
    statuses: [],
    hubSettings: null,
    selectedEdgeId: null,
    newEdgeId: null,
    isLoading: false,
    error: null,
    lastUpdated: 0,
  },
  'soft'
);

// Remote Ingress Standalone Functions
// ============================================================================

export async function fetchConnectionToken(edgeId: string) {
  const context = getActionContext();
  const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
    interfaces.requests.IReq_GetRemoteIngressConnectionToken
  >('/typedrequest', 'getRemoteIngressConnectionToken');
  return request.fire({ identity: context.identity!, edgeId });
}

// ============================================================================
// Remote Ingress Actions
// ============================================================================

export const fetchRemoteIngressAction = remoteIngressStatePart.createAction(async (statePartArg): Promise<IRemoteIngressState> => {
  const context = getActionContext();
  const currentState = statePartArg.getState()!;
  if (!context.identity) return currentState;

  try {
    const edgesRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetRemoteIngresses
    >('/typedrequest', 'getRemoteIngresses');

    const statusRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetRemoteIngressStatus
    >('/typedrequest', 'getRemoteIngressStatus');

    const hubSettingsRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetRemoteIngressHubSettings
    >('/typedrequest', 'getRemoteIngressHubSettings');

    const [edgesResponse, statusResponse, hubSettingsResponse] = await Promise.all([
      edgesRequest.fire({ identity: context.identity }),
      statusRequest.fire({ identity: context.identity }),
      hubSettingsRequest.fire({ identity: context.identity }),
    ]);

    return {
      ...currentState,
      edges: edgesResponse.edges,
      statuses: statusResponse.statuses,
      hubSettings: hubSettingsResponse.settings,
      isLoading: false,
      error: null,
      lastUpdated: Date.now(),
    };
  } catch (error) {
    return {
      ...currentState,
      isLoading: false,
      error: error instanceof Error ? error.message : 'Failed to fetch remote ingress data',
    };
  }
});

export const createRemoteIngressAction = remoteIngressStatePart.createAction<{
  name: string;
  listenPorts?: number[];
  autoDerivePorts?: boolean;
  performance?: interfaces.data.IRemoteIngressPerformanceConfig;
  tags?: string[];
}>(async (statePartArg, dataArg, actionContext): Promise<IRemoteIngressState> => {
  const context = getActionContext();
  const currentState = statePartArg.getState()!;

  try {
    const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_CreateRemoteIngress
    >('/typedrequest', 'createRemoteIngress');

    const response = await request.fire({
      identity: context.identity!,
      name: dataArg.name,
      listenPorts: dataArg.listenPorts,
      autoDerivePorts: dataArg.autoDerivePorts,
      performance: dataArg.performance,
      tags: dataArg.tags,
    });

    if (response.success) {
      // Refresh the list
      await actionContext!.dispatch(fetchRemoteIngressAction, null);

      return {
        ...statePartArg.getState()!,
        newEdgeId: response.edge.id,
      };
    }

    return currentState;
  } catch (error: unknown) {
    return {
      ...currentState,
      error: error instanceof Error ? error.message : 'Failed to create edge',
    };
  }
});

export const deleteRemoteIngressAction = remoteIngressStatePart.createAction<string>(
  async (statePartArg, edgeId, actionContext): Promise<IRemoteIngressState> => {
    const context = getActionContext();
    const currentState = statePartArg.getState()!;

    try {
      const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
        interfaces.requests.IReq_DeleteRemoteIngress
      >('/typedrequest', 'deleteRemoteIngress');

      await request.fire({
        identity: context.identity!,
        id: edgeId,
      });

      return await actionContext!.dispatch(fetchRemoteIngressAction, null);
    } catch (error: unknown) {
      return {
        ...currentState,
        error: error instanceof Error ? error.message : 'Failed to delete edge',
      };
    }
  }
);

export const updateRemoteIngressAction = remoteIngressStatePart.createAction<{
  id: string;
  name?: string;
  listenPorts?: number[];
  autoDerivePorts?: boolean;
  performance?: interfaces.data.IRemoteIngressPerformanceConfig;
  tags?: string[];
}>(async (statePartArg, dataArg, actionContext): Promise<IRemoteIngressState> => {
  const context = getActionContext();
  const currentState = statePartArg.getState()!;

  try {
    const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_UpdateRemoteIngress
    >('/typedrequest', 'updateRemoteIngress');

    await request.fire({
      identity: context.identity!,
      id: dataArg.id,
      name: dataArg.name,
      listenPorts: dataArg.listenPorts,
      autoDerivePorts: dataArg.autoDerivePorts,
      performance: dataArg.performance,
      tags: dataArg.tags,
    });

    return await actionContext!.dispatch(fetchRemoteIngressAction, null);
  } catch (error: unknown) {
    return {
      ...currentState,
      error: error instanceof Error ? error.message : 'Failed to update edge',
    };
  }
});

export const updateRemoteIngressHubSettingsAction = remoteIngressStatePart.createAction<{
  enabled?: boolean;
  tunnelPort?: number;
  hubDomain?: string | null;
  performance?: interfaces.data.IRemoteIngressPerformanceConfig | null;
}>(async (statePartArg, dataArg, actionContext): Promise<IRemoteIngressState> => {
  const context = getActionContext();
  const currentState = statePartArg.getState()!;

  try {
    const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_UpdateRemoteIngressHubSettings
    >('/typedrequest', 'updateRemoteIngressHubSettings');

    const response = await request.fire({
      identity: context.identity!,
      enabled: dataArg.enabled,
      tunnelPort: dataArg.tunnelPort,
      hubDomain: dataArg.hubDomain,
      performance: dataArg.performance,
    });

    if (!response.success) {
      return {
        ...currentState,
        error: response.message || 'Failed to update RemoteIngress hub settings',
      };
    }

    return await actionContext!.dispatch(fetchRemoteIngressAction, null);
  } catch (error: unknown) {
    return {
      ...currentState,
      error: error instanceof Error ? error.message : 'Failed to update RemoteIngress hub settings',
    };
  }
});

export const regenerateRemoteIngressSecretAction = remoteIngressStatePart.createAction<string>(
  async (statePartArg, edgeId): Promise<IRemoteIngressState> => {
    const context = getActionContext();
    const currentState = statePartArg.getState()!;

    try {
      const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
        interfaces.requests.IReq_RegenerateRemoteIngressSecret
      >('/typedrequest', 'regenerateRemoteIngressSecret');

      const response = await request.fire({
        identity: context.identity!,
        id: edgeId,
      });

      if (response.success) {
        return {
          ...currentState,
          newEdgeId: edgeId,
        };
      }

      return currentState;
    } catch (error) {
      return {
        ...currentState,
        error: error instanceof Error ? error.message : 'Failed to regenerate secret',
      };
    }
  }
);

export const clearNewEdgeIdAction = remoteIngressStatePart.createAction(
  async (statePartArg): Promise<IRemoteIngressState> => {
    return {
      ...statePartArg.getState()!,
      newEdgeId: null,
    };
  }
);

export const toggleRemoteIngressAction = remoteIngressStatePart.createAction<{
  id: string;
  enabled: boolean;
}>(async (statePartArg, dataArg, actionContext): Promise<IRemoteIngressState> => {
  const context = getActionContext();
  const currentState = statePartArg.getState()!;

  try {
    const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_UpdateRemoteIngress
    >('/typedrequest', 'updateRemoteIngress');

    await request.fire({
      identity: context.identity!,
      id: dataArg.id,
      enabled: dataArg.enabled,
    });

    return await actionContext!.dispatch(fetchRemoteIngressAction, null);
  } catch (error: unknown) {
    return {
      ...currentState,
      error: error instanceof Error ? error.message : 'Failed to toggle edge',
    };
  }
});
