import {
  Box,
  Divider,
  Dropdown,
  Text,
  TextButton,
  TableListItem,
  ListItemAction,
  listItemSelectBuilder,
  SectionHelper,
} from '@wix/design-system';
import { Add, ArrowRight } from '@wix/wix-ui-icons-common';
import { ImportState, NewFieldType } from '@wix/bex-core';
import { useTranslations } from '@wix/patterns-fields';
import React from 'react';
import { observer } from 'mobx-react-lite';
import { IdCollisionControl } from './ImportIdCollisionControl';

export interface ImportStepConfigurationProps {
  state: ImportState;
}

const COLUMN_WIDTHS = {
  title: 'minmax(0, 150px)',
  arrow: '1fr',
  field: 'minmax(0, 250px)',
};
const SCROLLBAR_GUTTER: React.CSSProperties = { scrollbarGutter: 'stable' };

// Synthetic dropdown option id representing "create a new field from this
// column". Distinct from any real field id (which never starts with `$`).
const CREATE_NEW_FIELD_OPTION_ID = '$createNewField';

// Translation key for each new-field type's name, injected (lowercased) into the
// helper text ("This will be a new {typeName} field."). Reuses the shared
// patterns-fields field-type names. Keyed by `NewFieldType` so adding a detected
// type makes the missing entry a compile error here — the single place to extend.
type FieldTypeTitleKey =
  | 'auto-patterns.fields.field_type_text_title'
  | 'auto-patterns.fields.field_type_number_title'
  | 'auto-patterns.fields.field_type_date_title'
  | 'auto-patterns.fields.field_type_boolean_title'
  | 'auto-patterns.fields.field_type_url_title'
  | 'auto-patterns.fields.field_type_image_title'
  | 'auto-patterns.fields.field_type_video_title'
  | 'auto-patterns.fields.field_type_document_title'
  | 'auto-patterns.fields.field_type_audio_title';

const NEW_FIELD_TYPE_TITLE_KEY: Record<NewFieldType, FieldTypeTitleKey> = {
  text: 'auto-patterns.fields.field_type_text_title',
  number: 'auto-patterns.fields.field_type_number_title',
  date: 'auto-patterns.fields.field_type_date_title',
  boolean: 'auto-patterns.fields.field_type_boolean_title',
  url: 'auto-patterns.fields.field_type_url_title',
  image: 'auto-patterns.fields.field_type_image_title',
  video: 'auto-patterns.fields.field_type_video_title',
  document: 'auto-patterns.fields.field_type_document_title',
  audio: 'auto-patterns.fields.field_type_audio_title',
};

type DropdownOption = ReturnType<typeof listItemSelectBuilder>;

interface NewFieldHelperTextProps {
  state: ImportState;
  header: string;
  fieldType: NewFieldType;
}

/**
 * Helper line under a "create new field" mapping (e.g. "This will be a new text
 * field.") followed by an "Edit field" link that opens the field editor. The
 * type name comes from the shared patterns-fields translations via
 * `useTranslations`, so this is only rendered when the import modal is wrapped in
 * `PatternsFieldsProvider` — which `ImportButtonModalLayout` does whenever field
 * creation is enabled (the only case a `new` mapping exists).
 */
const NewFieldHelperText = observer(function _NewFieldHelperText({
  state,
  header,
  fieldType,
}: NewFieldHelperTextProps) {
  const { t: ft } = useTranslations();
  const typeName = ft(NEW_FIELD_TYPE_TITLE_KEY[fieldType]).toLocaleLowerCase();

  return (
    <Box direction="horizontal" gap="SP1" verticalAlign="middle">
      <Text
        size="tiny"
        secondary
        dataHook={`import-new-field-helper-${header}`}
      >
        {state.translate('cairo.import.newFieldHelper', { typeName })}
      </Text>
      <TextButton
        size="tiny"
        dataHook={`import-edit-field-${header}`}
        onClick={() => state.beginFieldEdit(header)}
      >
        {state.translate('cairo.import.editField')}
      </TextButton>
    </Box>
  );
});

interface FieldMappingCellProps {
  state: ImportState;
  header: string;
  fieldOptions: DropdownOption[];
}

const FieldMappingCell = observer(function _FieldMappingCell({
  state,
  header,
  fieldOptions,
}: FieldMappingCellProps) {
  const { translate: t, selectedFieldIds, canCreateNewField } = state;
  const mapping = state.mappingByHeader[header];

  const selectedId =
    mapping?.kind === 'existing'
      ? mapping.fieldId
      : mapping?.kind === 'new'
      ? CREATE_NEW_FIELD_OPTION_ID
      : undefined;

  const options: DropdownOption[] = [
    ...fieldOptions.map((option) => ({
      ...option,
      disabled:
        selectedFieldIds.has(String(option.id)) &&
        !(
          mapping?.kind === 'existing' && mapping.fieldId === String(option.id)
        ),
    })),
    ...(canCreateNewField
      ? [
          // The new field's name — the display name the user entered in the
          // field editor once they've named it, otherwise the CSV column header
          // (the default the field is created with). Followed by a translated
          // "(New)" marker, built in code rather than via an interpolated key so
          // it always shows regardless of which translation bundle the consumer
          // loads.
          (() => {
            const newFieldName =
              mapping?.kind === 'new' && mapping.displayName
                ? mapping.displayName
                : header;
            const label = `${newFieldName} ${t('cairo.import.newFieldSuffix')}`;
            return listItemSelectBuilder({
              id: CREATE_NEW_FIELD_OPTION_ID,
              label,
              title: label,
            });
          })(),
        ]
      : []),
  ];

  return (
    <Box direction="vertical" gap="SP1">
      <Dropdown
        dataHook={`import-mapping-${header}`}
        clearButton
        onClear={() => {
          state.setMapping(header, null);
        }}
        placeholder={t('cairo.import.skipColumn')}
        selectedId={selectedId}
        onSelect={({ id }) => {
          if (id === CREATE_NEW_FIELD_OPTION_ID) {
            state.setNewFieldMapping(header);
          } else {
            state.setMapping(header, id as string);
          }
        }}
        popoverProps={{
          appendTo: 'window',
          zIndex: 5001,
          flip: true,
          fixed: false,
        }}
        options={options}
        fixedFooter={
          canCreateNewField ? (
            <div>
              {/* Separate the "Create new field" action from the field options
                  above it (CAIRO-4476). */}
              <Divider />
              <ListItemAction
                size="small"
                skin="primary"
                prefixIcon={<Add />}
                dataHook={`import-create-field-${header}`}
                title={t('cairo.import.createNewField')}
                // Map the column to a new field, then open the editor on it — the
                // editor component (renderFieldEditor) reacts to `editingHeader`.
                onClick={() => {
                  state.setNewFieldMapping(header);
                  state.beginFieldEdit(header);
                }}
              />
            </div>
          ) : undefined
        }
        size="small"
      />
      {mapping?.kind === 'new' && (
        <NewFieldHelperText
          state={state}
          header={header}
          fieldType={mapping.fieldType}
        />
      )}
      {state.canConfigureWritePolicy && state.idMappedHeader === header && (
        <IdCollisionControl state={state} />
      )}
    </Box>
  );
});

function _ImportStepConfiguration({ state }: ImportStepConfigurationProps) {
  const { csvHeaders, fields, translate: t } = state;

  // Row order is snapshotted per file in state, with the `_id`-mapped column
  // floated to the top (CAIRO-4418). It stays fixed while the user edits
  // mappings, so clearing/remapping the `_id` column doesn't reorder the row
  // under the cursor. Fall back to CSV order if the snapshot isn't populated.
  const orderedHeaders =
    state.orderedHeaders.length > 0 ? state.orderedHeaders : csvHeaders;

  const baseDropdownOptions = fields
    .filter((field) => field.id != null)
    .map((field) =>
      listItemSelectBuilder({
        id: field.id!,
        label: field.header,
        title: field.header,
      }),
    );

  const hasNoRows = state.hasNoMappedData;

  return (
    <Box direction="vertical" dataHook="import-mapping-step" gap="SP3">
      {hasNoRows && (
        <Box padding="0 SP4">
          <SectionHelper
            dataHook="import-no-rows-warning"
            skin="warning"
            title={t('cairo.import.noRowsWarningTitle')}
          >
            {t('cairo.import.noRowsWarningDescription')}
          </SectionHelper>
        </Box>
      )}

      <Box direction="vertical" flex={1} minHeight={0}>
        <Box
          display="grid"
          direction="horizontal"
          gap="SP4"
          padding="SP2 SP4"
          backgroundColor="var(--wds-color-fill-surface-neutral,var(--wsr-color-D75, #F7F8F8))"
          boxShadow="inset 0 1px 0 0 var(--wds-color-border-dark-secondary, var(--wsr-color-D60, #DFE5EB)), inset 0 -1px 0 0 var(--wds-color-border-dark-secondary, var(--wsr-color-D60, #DFE5EB))"
          gridTemplateColumns={`${COLUMN_WIDTHS.title} ${COLUMN_WIDTHS.arrow} ${COLUMN_WIDTHS.field}`}
          flexShrink={0}
          style={SCROLLBAR_GUTTER}
        >
          <Box minWidth={0} direction="vertical">
            <Text size="small" weight="thin" ellipsis>
              {t('cairo.import.columnTitle')}
            </Text>
          </Box>

          <Box minWidth={0} direction="vertical" />

          <Box minWidth={0} direction="vertical">
            <Text size="small" weight="thin" ellipsis>
              {t('cairo.import.collectionField')}
            </Text>
          </Box>
        </Box>

        <Box
          direction="vertical"
          overflowY="auto"
          maxHeight={hasNoRows ? 'calc(80vh - 420px)' : 'calc(80vh - 300px)'}
          style={SCROLLBAR_GUTTER}
        >
          {orderedHeaders.map((header, index) => (
            <TableListItem
              key={header}
              showDivider={index < orderedHeaders.length - 1}
              options={[
                {
                  value: (
                    <Text ellipsis size="small" dataHook="import-column-title">
                      {header}
                    </Text>
                  ),
                  width: COLUMN_WIDTHS.title,
                },
                {
                  value: (
                    <Box align="center">
                      <ArrowRight />
                    </Box>
                  ),
                  width: COLUMN_WIDTHS.arrow,
                },
                {
                  value: (
                    <FieldMappingCell
                      state={state}
                      header={header}
                      fieldOptions={baseDropdownOptions}
                    />
                  ),
                  width: COLUMN_WIDTHS.field,
                },
              ]}
            />
          ))}
        </Box>
      </Box>
    </Box>
  );
}

export const ImportStepConfiguration = observer(_ImportStepConfiguration);
