import React, { useState } from 'react';
import { observer } from 'mobx-react-lite';
import { useWixPatternsContainer } from '@wix/bex-core/react';
import {
  Box,
  Card,
  Cell,
  Layout,
  SkeletonLine,
  Text,
  TextButton,
} from '@wix/design-system';
import { CardContainer } from '../CardContainer';
import { TagsWidgetContextProvider } from '../TagsWidgetContext';
import { TagsWidgetContent } from './TagsWidgetContent';
import { Tags, OnSubmitTagsFuncType, TagsWidgetState } from '@wix/bex-core';
import { useWidgetPageStatus } from '../useWidgetPageStatus';
import { Refresh } from '@wix/wix-ui-icons-common';
import { useTagsWidgetInternal } from '../../hooks/useTagsWidget';

export type TagsWidgetProps = {
  /**
   * The FQDN of the entity.
   */
  fqdn?: string;

  /**
   * A string that represents the name of the entity type (e.g., "Orders"),
   * displayed as the title of the manage tags modal.
   */
  entityTypeName: string;
  /**
   * A string that represents the ID of the current entity.
   */
  entityId?: string | null;
  /**
   * Tags object associated with the entity when the widget is loaded.
   */
  initialTags?: Tags;
  /**
   * A subtitle to show on the tags widget card. Relevant for the default card theme only.
   */
  subtitle?: string;
  /**
   * Applies a `data-hook` HTML attribute that can be used in tests.
   */
  dataHook?: string;
  /**
   * A callback function that is called when a user adds or removes tags from the entity.
   * @param tags - An object containing:
   * `allTags`: The updated tags object containing both private and public tags. \
   * `addedTags`: An array of added tags. \
   * `removedTags`: An array of removed tags.
   */
  onSubmit?: OnSubmitTagsFuncType;
  /**
   * The origin of the widget.
   */
  origin?: string;
  /**
   * The theme of the tags widget.
   */
  theme?: 'card' | 'inline';

  /**
   * Displays tags without the option to edit them.
   */
  readOnly?: boolean;
} & (
  | {
      /**
       * The FQDN used to extract the schema from the data-extension service.
       */
      fqdn: string;

      /**
       * The widget state (should not be used when `fqdn` is provided).
       */
      state?: never;
    }
  | {
      /**
       * The widget state (should be used when `fqdn` is not provided).
       */
      state: TagsWidgetState;

      /**
       * The FQDN should not be provided if `state` is specified.
       */
      fqdn?: never;
    }
);

export { OnSubmitTagsFuncType };

export interface TagsWidgetBaseProps
  extends Omit<TagsWidgetProps, 'origin' | 'fqdn'> {}

const InlineLayoutContent = ({
  dataHook,
  state: _state,
  ...contentProps
}: TagsWidgetBaseProps) => {
  const { translate: t } = useWixPatternsContainer();
  const state = _state!;
  const { status } = useWidgetPageStatus(state.initTask.status.status);

  if (status === 'idle' || status === 'loading') {
    return (
      <Layout>
        <Cell span={8}>
          <div data-hook={dataHook}>
            <SkeletonLine
              marginBottom="7px"
              marginTop="7px"
              dataHook="tags-widget-skeleton"
            />
          </div>
        </Cell>
      </Layout>
    );
  }

  if (status === 'error') {
    return (
      <Box justifyItems="center" gap="tiny" dataHook={dataHook}>
        <Text dataHook="tags-widget-error-text">
          {t('cairo.tags.loadTags.error.body')}
        </Text>
        <TextButton dataHook="tags-widget-retry-button" onClick={state.retry}>
          {t('cairo.tags.loadTags.error.CTA')}
        </TextButton>
      </Box>
    );
  }

  return (
    <div data-hook={dataHook}>
      <TagsWidgetContent {...contentProps} state={state} />
    </div>
  );
};

const _TagsWidgetBase = ({
  subtitle,
  dataHook,
  theme,
  state: _state,
  ...contentProps
}: TagsWidgetBaseProps) => {
  const { translate: t } = useWixPatternsContainer();

  const state = _state!;
  const { status } = useWidgetPageStatus(state.initTask.status.status);

  if (theme === 'inline') {
    return (
      <InlineLayoutContent
        dataHook={dataHook}
        state={state}
        {...contentProps}
      />
    );
  }

  return (
    <CardContainer
      dataHook={dataHook}
      status={status}
      errorState={{
        dataHook: 'error-state',
        subtitle: t('cairo.tags.loadTags.error.body'),
        action: {
          text: t('cairo.tags.loadTags.error.CTA'),
          prefixIcon: <Refresh />,
          onClick: state.retry,
        },
      }}
    >
      <Card.Header
        dataHook="tags-widget-card-header"
        title={t('cairo.tags.tagsWidget.title')}
        subtitle={subtitle || t('cairo.tags.tagsWidget.subtitle')}
      />
      <Card.Divider />
      <Card.Content dataHook="tags-widget-card-content">
        <TagsWidgetContent state={state} {...contentProps} />
      </Card.Content>
    </CardContainer>
  );
};

export const TagsWidgetBase = observer(_TagsWidgetBase);

const _TagsWidget = (props: TagsWidgetProps) => {
  const { origin, fqdn, state: externalState, ...baseComponentProps } = props;

  const internalState = useTagsWidgetInternal({
    origin,
    fqdn,
  });

  const [state] = useState(() => externalState ?? internalState);

  return (
    <TagsWidgetContextProvider value={state}>
      <TagsWidgetBase state={state} {...baseComponentProps} />
    </TagsWidgetContextProvider>
  );
};

export const TagsWidget = observer(_TagsWidget);
