import React from 'react';
import {
  registerCrmActionHandlers,
  type CrmActionHandlerHost,
} from './action-handlers';
import {
  createCrmActivityTimelineAdapters,
  type CrmActivityTimelineActionConfig,
  type CrmActivityTimelineAdapterOptions,
  type CrmActivityTimelineObjectMetadata,
  type CrmActivityTimelinePanelProps,
  type CrmActivityTimelineStandardAction,
} from './activity-timeline-adapter';
import {
  createCrmRecordActivityFeedAdapters,
  type CrmRecordActivityFeedAdapterOptions,
} from './record-activity-feed-adapter';
import { salesforceCurrencyDisplayPolicy } from './currency-display-policy';
import {
  createCrmFrontendHostContribution,
  crmFrontendSourceContribution,
  type CrmFrontendHostContribution,
  type CrmFrontendRouteComponentHost,
} from './frontend-contribution';
import {
  registerCrmDashboardWidgetContribution,
  registerCrmMetadataContribution,
  registerCrmSetupContribution,
  registerCrmUiFieldContribution,
  type CrmDashboardWidgetContributionHost,
  type CrmMetadataContributionHost,
  type CrmRuntimeSetupPageDefinition,
  type CrmSetupContributionHost,
  type CrmUiFieldContributionHost,
} from './host-contributions';
import {
  CRM_ACTIVITY_TIMELINE_RENDERER_ID,
  CRM_CONVERTED_LEAD_BANNER_RENDERER_ID,
  CRM_CREATE_RECORD_FROM_SOURCE_RENDERER_ID,
  CRM_EMAIL_COMPOSE_RENDERER_ID,
  CRM_LEAD_CONVERT_RENDERER_ID,
  CRM_RECORD_ACTIVITY_FEED_RENDERER_ID,
  CRM_RECORD_CHILD_BAR_CHART_RENDERER_ID,
  CRM_TASK_ACTIVITY_QUICK_CREATE_RENDERER_ID,
} from './renderer-ids';
import {
  createCrmRuntimeRendererAdapters,
  type CrmRuntimeActionRendererProps,
  type CrmRuntimeRecordPanelProps,
  type CrmRuntimeRendererAdapterOptions,
} from './runtime-renderer-adapters';
import type {
  CrmAppNavigationCapabilityDefinition,
  CrmStandardPageTabDefinition,
} from './route-surface-policy';
import type {
  CrmSetupChildRouteDefinition,
  CrmSetupPageCapabilityDefinition,
} from './setup-navigation-policy';
import type {
  CrmUiFieldInputProps,
  CrmUiFieldRendererProps,
} from './ui-field-components';

export const CRM_APP_CONFIG_FRONTEND_OWNER_SOURCE = 'salesforce-ui-api';

export interface CrmFrontendHostRendererAdapters<
  TActionRendererProps extends CrmRuntimeActionRendererProps,
  TRecordPanelProps extends CrmRuntimeRecordPanelProps,
  THostRenderer,
> {
  createActionRendererHostAdapter: (component: React.FC<TActionRendererProps>) => THostRenderer;
  createRecordPanelHostAdapter: (component: React.FC<TRecordPanelProps>) => THostRenderer;
  registerActionRendererHostAdapter: (rendererId: string, renderer: THostRenderer) => void;
  registerRecordPanelHostAdapter: (rendererId: string, renderer: THostRenderer) => void;
}

export interface CrmFrontendSurfaceRegistrationHost {
  registerAppConfigFrontendOwner: (
    source: string,
    appId: string,
    options: { fallback?: boolean },
  ) => void;
  registerCurrencyDisplayPolicy: (policy: typeof salesforceCurrencyDisplayPolicy) => void;
  registerSetupSurface: (surface: typeof crmFrontendSourceContribution.setupSurface) => void;
  registerSetupPageCapabilities: (
    appId: string,
    capabilities: readonly CrmSetupPageCapabilityDefinition[],
  ) => void;
  registerAppNavigationCapabilities: (
    appId: string,
    capabilities: readonly CrmAppNavigationCapabilityDefinition[],
  ) => void;
  registerEmailAlertRecipientTypes: (
    types: typeof crmFrontendSourceContribution.emailAlertRecipientTypes,
  ) => void;
  registerHostApp: (contribution: CrmFrontendHostContribution) => void;
  registerStandardPageTabs: (
    appId: string,
    tabs: readonly CrmStandardPageTabDefinition[],
  ) => void;
}

export interface CrmFrontendSetupRegistrationHost<TComponent>
  extends Omit<CrmSetupContributionHost<TComponent>, 'registerPages' | 'registerChildRoutes'> {
  registerPages: (appId: string, pages: readonly CrmRuntimeSetupPageDefinition[]) => void;
  registerChildRoutes: (appId: string, routes: readonly CrmSetupChildRouteDefinition[]) => void;
}

export interface CrmFrontendHostAdapterHost<
  TActionRendererProps extends CrmRuntimeActionRendererProps,
  TRecordPanelProps extends CrmRuntimeRecordPanelProps & CrmActivityTimelinePanelProps<TObjectMetadata, TActionConfig>,
  THostRenderer,
  TSetupComponent,
  TDashboardWidget,
  TFieldType extends string,
  TOperator extends string,
  TFieldRenderer extends React.FC<CrmUiFieldRendererProps>,
  TFieldInput extends React.FC<CrmUiFieldInputProps>,
  TStandardAction extends CrmActivityTimelineStandardAction,
  TActionConfig extends CrmActivityTimelineActionConfig,
  TObjectMetadata extends CrmActivityTimelineObjectMetadata,
> extends CrmFrontendRouteComponentHost {
  surfaces: CrmFrontendSurfaceRegistrationHost;
  rendererAdapters: CrmFrontendHostRendererAdapters<TActionRendererProps, TRecordPanelProps, THostRenderer>;
  actionHandlers: CrmActionHandlerHost;
  runtimeRenderers: CrmRuntimeRendererAdapterOptions;
  activityTimeline: CrmActivityTimelineAdapterOptions<TStandardAction, TActionConfig, TObjectMetadata>;
  recordActivityFeed: CrmRecordActivityFeedAdapterOptions;
  recordChildBarChart: React.FC<TRecordPanelProps>;
  dashboardWidgets: CrmDashboardWidgetContributionHost<TDashboardWidget>;
  metadata: CrmMetadataContributionHost<TFieldType, TOperator>;
  setup: CrmFrontendSetupRegistrationHost<TSetupComponent>;
  uiFields: CrmUiFieldContributionHost<TFieldRenderer, TFieldInput>;
}

export interface CrmFrontendHostAdapterRegistration<THostRenderer> {
  contribution: CrmFrontendHostContribution & {
    actionRenderers: Array<[string, THostRenderer]>;
    panelRenderers: Array<[string, THostRenderer]>;
  };
  actionRenderers: {
    leadConvert: THostRenderer;
    createRecordFromSource: THostRenderer;
    taskActivityQuickCreate: THostRenderer;
    emailCompose: THostRenderer;
  };
  panelRenderers: {
    activityTimeline: THostRenderer;
    recordActivityFeed: THostRenderer;
    recordChildBarChart: THostRenderer;
    convertedLeadBanner: THostRenderer;
  };
}

export function createCrmFrontendHostAdapterRegistration<
  TActionRendererProps extends CrmRuntimeActionRendererProps,
  TRecordPanelProps extends CrmRuntimeRecordPanelProps & CrmActivityTimelinePanelProps<TObjectMetadata, TActionConfig>,
  THostRenderer,
  TSetupComponent,
  TDashboardWidget,
  TFieldType extends string,
  TOperator extends string,
  TFieldRenderer extends React.FC<CrmUiFieldRendererProps>,
  TFieldInput extends React.FC<CrmUiFieldInputProps>,
  TStandardAction extends CrmActivityTimelineStandardAction,
  TActionConfig extends CrmActivityTimelineActionConfig,
  TObjectMetadata extends CrmActivityTimelineObjectMetadata,
>(
  host: CrmFrontendHostAdapterHost<
    TActionRendererProps,
    TRecordPanelProps,
    THostRenderer,
    TSetupComponent,
    TDashboardWidget,
    TFieldType,
    TOperator,
    TFieldRenderer,
    TFieldInput,
    TStandardAction,
    TActionConfig,
    TObjectMetadata
  >,
): CrmFrontendHostAdapterRegistration<THostRenderer> {
  const runtimeRenderers = createCrmRuntimeRendererAdapters<TActionRendererProps, TRecordPanelProps>(
    host.runtimeRenderers,
  );
  const activityTimeline = createCrmActivityTimelineAdapters<
    TStandardAction,
    TActionConfig,
    TObjectMetadata,
    TRecordPanelProps
  >(host.activityTimeline);
  const recordActivityFeed = createCrmRecordActivityFeedAdapters<TRecordPanelProps>(host.recordActivityFeed);

  const actionRenderers = {
    leadConvert: host.rendererAdapters.createActionRendererHostAdapter(runtimeRenderers.ConvertLeadModal),
    createRecordFromSource: host.rendererAdapters.createActionRendererHostAdapter(
      runtimeRenderers.CreateRecordFromSourceModal,
    ),
    taskActivityQuickCreate: host.rendererAdapters.createActionRendererHostAdapter(
      runtimeRenderers.TaskActivityQuickCreateModal,
    ),
    emailCompose: host.rendererAdapters.createActionRendererHostAdapter(
      runtimeRenderers.SendRecordEmailModal,
    ),
  };
  const panelRenderers = {
    activityTimeline: host.rendererAdapters.createRecordPanelHostAdapter(activityTimeline.CRMActivityTimelinePanel),
    recordActivityFeed: host.rendererAdapters.createRecordPanelHostAdapter(recordActivityFeed.CRMRecordActivityFeedPanel),
    recordChildBarChart: host.rendererAdapters.createRecordPanelHostAdapter(host.recordChildBarChart),
    convertedLeadBanner: host.rendererAdapters.createRecordPanelHostAdapter(runtimeRenderers.ConvertedLeadBanner),
  };

  return {
    contribution: createCrmFrontendHostContribution<THostRenderer>({
      routeComponents: host.routeComponents,
      createRedirectRoute: host.createRedirectRoute,
      renderers: {
        ...actionRenderers,
        ...panelRenderers,
      },
    }),
    actionRenderers,
    panelRenderers,
  };
}

export function registerCrmFrontendHostAdapter<
  TActionRendererProps extends CrmRuntimeActionRendererProps,
  TRecordPanelProps extends CrmRuntimeRecordPanelProps & CrmActivityTimelinePanelProps<TObjectMetadata, TActionConfig>,
  THostRenderer,
  TSetupComponent,
  TDashboardWidget,
  TFieldType extends string,
  TOperator extends string,
  TFieldRenderer extends React.FC<CrmUiFieldRendererProps>,
  TFieldInput extends React.FC<CrmUiFieldInputProps>,
  TStandardAction extends CrmActivityTimelineStandardAction,
  TActionConfig extends CrmActivityTimelineActionConfig,
  TObjectMetadata extends CrmActivityTimelineObjectMetadata,
>(
  host: CrmFrontendHostAdapterHost<
    TActionRendererProps,
    TRecordPanelProps,
    THostRenderer,
    TSetupComponent,
    TDashboardWidget,
    TFieldType,
    TOperator,
    TFieldRenderer,
    TFieldInput,
    TStandardAction,
    TActionConfig,
    TObjectMetadata
  >,
): CrmFrontendHostAdapterRegistration<THostRenderer> {
  const registration = createCrmFrontendHostAdapterRegistration(host);
  const appId = crmFrontendSourceContribution.appId;

  host.surfaces.registerAppConfigFrontendOwner(CRM_APP_CONFIG_FRONTEND_OWNER_SOURCE, appId, {
    fallback: true,
  });
  registerCrmActionHandlers(host.actionHandlers);
  registerCrmMetadataContribution(host.metadata);
  registerCrmUiFieldContribution(host.uiFields);
  registerCrmDashboardWidgetContribution(host.dashboardWidgets);
  host.surfaces.registerCurrencyDisplayPolicy(crmFrontendSourceContribution.currencyDisplayPolicy);
  host.surfaces.registerSetupSurface(crmFrontendSourceContribution.setupSurface);
  host.surfaces.registerSetupPageCapabilities(appId, crmFrontendSourceContribution.setupPageCapabilities);
  host.surfaces.registerAppNavigationCapabilities(appId, crmFrontendSourceContribution.appNavigationCapabilities);
  registerCrmSetupContribution(host.setup);
  host.surfaces.registerEmailAlertRecipientTypes(crmFrontendSourceContribution.emailAlertRecipientTypes);
  host.surfaces.registerHostApp(registration.contribution);
  host.surfaces.registerStandardPageTabs(appId, crmFrontendSourceContribution.standardPageTabs);
  host.rendererAdapters.registerActionRendererHostAdapter(
    CRM_LEAD_CONVERT_RENDERER_ID,
    registration.actionRenderers.leadConvert,
  );
  host.rendererAdapters.registerActionRendererHostAdapter(
    CRM_CREATE_RECORD_FROM_SOURCE_RENDERER_ID,
    registration.actionRenderers.createRecordFromSource,
  );
  host.rendererAdapters.registerActionRendererHostAdapter(
    CRM_TASK_ACTIVITY_QUICK_CREATE_RENDERER_ID,
    registration.actionRenderers.taskActivityQuickCreate,
  );
  host.rendererAdapters.registerActionRendererHostAdapter(
    CRM_EMAIL_COMPOSE_RENDERER_ID,
    registration.actionRenderers.emailCompose,
  );
  host.rendererAdapters.registerRecordPanelHostAdapter(
    CRM_ACTIVITY_TIMELINE_RENDERER_ID,
    registration.panelRenderers.activityTimeline,
  );
  host.rendererAdapters.registerRecordPanelHostAdapter(
    CRM_RECORD_ACTIVITY_FEED_RENDERER_ID,
    registration.panelRenderers.recordActivityFeed,
  );
  host.rendererAdapters.registerRecordPanelHostAdapter(
    CRM_RECORD_CHILD_BAR_CHART_RENDERER_ID,
    registration.panelRenderers.recordChildBarChart,
  );
  host.rendererAdapters.registerRecordPanelHostAdapter(
    CRM_CONVERTED_LEAD_BANNER_RENDERER_ID,
    registration.panelRenderers.convertedLeadBanner,
  );

  return registration;
}
