import React, { memo, useState } from 'react';
import styled from 'styled-components';

import type { JSX } from 'react';

import {
  FeedbackType,
  type SearchAiMessageResource,
  type ToolCall,
  type ContentSegment,
} from '@redocly/theme/core/types';
import { TOOL_CALL_DISPLAY_TEXT } from '@redocly/theme/core/constants';
import { Link } from '@redocly/theme/components/Link/Link';
import { Tag } from '@redocly/theme/components/Tag/Tag';
import { AiSearchConversationRole } from '@redocly/theme/core/constants';
import { useThemeHooks } from '@redocly/theme/core/hooks';
import { Markdown } from '@redocly/theme/components/Markdown/Markdown';
import { DocumentIcon } from '@redocly/theme/icons/DocumentIcon/DocumentIcon';
import { AiStarsIcon } from '@redocly/theme/icons/AiStarsIcon/AiStarsIcon';
import { CheckmarkOutlineIcon } from '@redocly/theme/icons/CheckmarkOutlineIcon/CheckmarkOutlineIcon';
import { SearchAiActionButtons } from '@redocly/theme/components/Search/SearchAiActionButtons';
import { SearchAiNegativeFeedbackForm } from '@redocly/theme/components/Search/SearchAiNegativeFeedbackForm';

function MarkdownSegment({ text }: { text: string }): JSX.Element {
  const { useMarkdownText } = useThemeHooks();
  const markdown = useMarkdownText(text);
  return <ResponseText as="div" children={markdown} data-testid="response-text" />;
}
function getToolCallDisplayText(toolName: string): {
  inProgressText: string;
  completedText: string;
} {
  return (
    TOOL_CALL_DISPLAY_TEXT[toolName] ?? {
      inProgressText: `Executing ${toolName}...`,
      completedText: `${toolName} executed`,
    }
  );
}

export type SearchAiMessageProps = {
  role: AiSearchConversationRole;
  content: string;
  isThinking?: boolean;
  resources?: SearchAiMessageResource[];
  className?: string;
  messageId?: string;
  feedback?: FeedbackType;
  onFeedbackChange: (messageId: string, feedback: FeedbackType | undefined) => void;
  toolCalls?: ToolCall[];
  contentSegments?: ContentSegment[];
};

function SearchAiMessageComponent({
  role,
  content,
  isThinking,
  resources,
  className,
  messageId,
  feedback,
  onFeedbackChange,
  toolCalls = [],
  contentSegments = [{ type: 'text' as const, text: content }],
}: SearchAiMessageProps): JSX.Element {
  const { useTranslate, useTelemetry } = useThemeHooks();
  const { translate } = useTranslate();
  const telemetry = useTelemetry();
  const [feedbackSent, setFeedbackSent] = useState(false);

  const hasResources = !isThinking && resources && resources.length > 0;
  const resourcesCount = resources?.length ?? 0;

  const showSuccessMessage = feedbackSent && feedback;

  const isLoading = isThinking && content.length === 0 && toolCalls.length === 0;

  const sendFeedbackTelemetry = (feedbackValue: FeedbackType, dislikeReason?: string) => {
    if (!messageId) return;

    try {
      telemetry.sendSearchAIFeedbackMessage([
        {
          object: 'feedback',
          feedback: feedbackValue,
          messageId,
          reason: dislikeReason,
        },
      ]);
    } catch (error) {
      console.error('Error sending feedback', error);
    }
  };

  const handleFeedbackClick = (feedbackValue: FeedbackType, reason?: string) => {
    if (!messageId) {
      return;
    }

    if (!reason) {
      onFeedbackChange(messageId, feedbackValue);
    }

    sendFeedbackTelemetry(feedbackValue, reason);

    if (feedbackValue === FeedbackType.Like || reason) {
      setFeedbackSent(true);
    }
  };

  return (
    <SearchAiMessageWrapper
      data-component-name="Search/SearchAiMessage"
      role={role}
      className={className}
      data-testid="search-ai-message"
    >
      {role === AiSearchConversationRole.ASSISTANT && (
        <AiStarsIcon
          size="32px"
          background="var(--search-ai-icon-bg-color)"
          borderRadius="var(--border-radius-lg)"
          color="var(--search-ai-icon-color)"
          margin="0 var(--spacing-xs) 0 0"
        />
      )}
      <MessageContentWrapper>
        {role === AiSearchConversationRole.ASSISTANT ? (
          <>
            <MessageWrapper role={role}>
              {contentSegments.map((segment, index) => {
                if (segment.type === 'tool') {
                  const toolCallCompleted = Boolean(segment.toolCall.result);

                  const { inProgressText, completedText } = getToolCallDisplayText(
                    segment.toolCall.name,
                  );

                  const toolCallDisplayText = toolCallCompleted ? completedText : inProgressText;

                  return (
                    <ToolCallsInfoWrapper key={`tool-${index}`} data-testid="tool-calls-info">
                      <ToolCallInfoItem>
                        <DocumentIcon size="14px" color="--search-ai-text-color" />
                        <ToolCallText $isSearching={!toolCallCompleted}>
                          {toolCallDisplayText}
                        </ToolCallText>
                      </ToolCallInfoItem>
                    </ToolCallsInfoWrapper>
                  );
                }

                return <MarkdownSegment key={`text-${index}`} text={segment.text} />;
              })}
              {hasResources && (
                <>
                  <ResourcesWrapper data-testid="resources-wrapper">
                    <ResourcesTitle data-translation-key="search.ai.resourcesFound">
                      {translate('search.ai.resourcesFound.basedOn', 'Based on')} {resourcesCount}{' '}
                      {translate('search.ai.resourcesFound.resources', 'resources')}
                    </ResourcesTitle>
                    <ResourceTagsWrapper>
                      {resources?.map((resource, index) => (
                        <Link key={`${resource.url}-${index}`} to={resource.url} target="_blank">
                          <ResourceTag
                            borderless
                            icon={<DocumentIcon color="--search-ai-resource-tag-icon-color" />}
                          >
                            {resource.title}
                          </ResourceTag>
                        </Link>
                      ))}
                    </ResourceTagsWrapper>
                  </ResourcesWrapper>
                </>
              )}
              {isLoading && (
                <ThinkingDotsWrapper data-testid="thinking-dots-wrapper">
                  <ThinkingDot />
                  <ThinkingDot />
                  <ThinkingDot />
                </ThinkingDotsWrapper>
              )}
              {content.length > 0 && (
                <FeedbackWrapper>
                  <SearchAiActionButtons
                    content={content}
                    feedback={feedback}
                    onFeedback={handleFeedbackClick}
                    disabled={!!feedback}
                  />
                </FeedbackWrapper>
              )}
            </MessageWrapper>
            {messageId && feedback === FeedbackType.Dislike && !showSuccessMessage && (
              <SearchAiNegativeFeedbackForm
                messageId={messageId}
                onClose={(messageId: string, feedback: FeedbackType) => {
                  onFeedbackChange(messageId, feedback);
                  setFeedbackSent(true);
                }}
                onSubmit={(reason) => handleFeedbackClick(FeedbackType.Dislike, reason)}
              />
            )}
            {showSuccessMessage && (
              <SuccessMessageWrapper data-component-name="Search/SearchAiMessage/Success">
                <CheckmarkOutlineIcon size="20px" color="var(--color-success-base)" />
                <SuccessMessageText>
                  {translate('search.ai.feedback.thanks', 'Thank you for your feedback!')}
                </SuccessMessageText>
              </SuccessMessageWrapper>
            )}
          </>
        ) : (
          <MessageWrapper role={role}>{content}</MessageWrapper>
        )}
      </MessageContentWrapper>
    </SearchAiMessageWrapper>
  );
}

function areResourcesEqual(
  prev?: SearchAiMessageResource[],
  next?: SearchAiMessageResource[],
): boolean {
  if (prev === next) return true;

  if (!prev || !next || prev.length !== next.length) return false;

  return prev.every((resource, index) => {
    const nextResource = next[index];
    return resource.url === nextResource.url && resource.title === nextResource.title;
  });
}

export const SearchAiMessage = memo(SearchAiMessageComponent, (prevProps, nextProps) => {
  return (
    prevProps.role === nextProps.role &&
    prevProps.content === nextProps.content &&
    prevProps.isThinking === nextProps.isThinking &&
    prevProps.messageId === nextProps.messageId &&
    prevProps.feedback === nextProps.feedback &&
    prevProps.onFeedbackChange === nextProps.onFeedbackChange &&
    areResourcesEqual(prevProps.resources, nextProps.resources) &&
    prevProps.toolCalls?.length === nextProps.toolCalls?.length &&
    prevProps.contentSegments === nextProps.contentSegments
  );
});

const SearchAiMessageWrapper = styled.div<{ role: string }>`
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  width: 100%;
  justify-content: ${({ role }) =>
    role === AiSearchConversationRole.USER ? 'flex-end' : 'flex-start'};
`;

const MessageContentWrapper = styled.div`
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
  max-width: 80%;
  min-width: 0;
`;

const ResponseText = styled(Markdown)`
  color: var(--search-ai-text-color);
  font-size: var(--search-ai-text-font-size);
  line-height: var(--search-ai-text-line-height);
  font-family: inherit;
  white-space: break-spaces;

  article {
    > *:first-child {
      margin-top: 0;
    }
    > *:last-child {
      margin-bottom: 0;
    }
  }
`;

const MessageWrapper = styled.div<{ role: string }>`
  padding: ${({ role }) =>
    role === AiSearchConversationRole.USER
      ? 'var(--spacing-sm)'
      : 'var(--spacing-sm) var(--spacing-sm) var(--spacing-xs) var(--spacing-sm)'};
  border-radius: var(--border-radius-lg);
  width: fit-content;
  max-width: 100%;
  word-wrap: break-word;
  white-space: pre-wrap;
  background-color: ${({ role }) =>
    role === AiSearchConversationRole.USER
      ? 'var(--search-ai-user-bg-color)'
      : 'var(--search-ai-assistant-bg-color)'};
  border: ${({ role }) =>
    role === AiSearchConversationRole.USER ? 'none' : 'var(--search-ai-assistant-border)'};
  color: ${({ role }) =>
    role === AiSearchConversationRole.USER
      ? 'var(--search-ai-user-text-color)'
      : 'var(--search-ai-assistant-text-color)'};
`;

const ResourcesWrapper = styled.div`
  gap: var(--search-ai-resources-gap);
  display: flex;
  flex-direction: column;
  margin: 0;
`;
const FeedbackWrapper = styled.div`
  display: flex;
  flex-direction: row;
  gap: var(--search-ai-feedback-gap);
  margin-top: var(--spacing-sm);
`;

const ResourcesTitle = styled.div`
  font-weight: var(--search-ai-resources-title-font-weight);
  font-size: var(--search-ai-resources-title-font-size);
  line-height: var(--search-ai-resources-title-line-height);
`;

const ResourceTagsWrapper = styled.div`
  display: flex;
  flex-wrap: wrap;
  gap: var(--search-ai-resource-tags-gap);
`;

const ResourceTag = styled(Tag)`
  .tag-default {
    --tag-color: var(--search-ai-resource-tag-text-color);
    max-width: 100%;
    overflow: hidden;
    display: inline-block;
  }
  svg {
    min-width: var(--search-ai-resource-tag-icon-size);
    min-height: var(--search-ai-resource-tag-icon-size);
    flex-shrink: 0;
  }
  > div {
    overflow: hidden;
    word-break: break-word;
    white-space: normal;
    max-width: 100%;
  }
`;

const ThinkingDotsWrapper = styled.div`
  display: flex;
  gap: var(--search-ai-thinking-dots-gap);
  padding: var(--search-ai-thinking-dots-padding);
`;

const ThinkingDot = styled.div`
  width: var(--search-ai-thinking-dot-size);
  height: var(--search-ai-thinking-dot-size);
  border-radius: 50%;
  background: var(--search-ai-thinking-dot-color);
  animation: bounce 1.4s infinite ease-in-out;

  &:nth-child(1) {
    animation-delay: -0.32s;
  }
  &:nth-child(2) {
    animation-delay: -0.16s;
  }
  &:nth-child(3) {
    animation-delay: 0s;
  }

  @keyframes bounce {
    0%,
    80%,
    100% {
      opacity: 0.2;
      transform: scale(0.8);
    }
    40% {
      opacity: 1;
      transform: scale(1);
    }
  }
`;

const SuccessMessageWrapper = styled.div`
  max-width: fit-content;
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  padding: var(--spacing-sm);
  background: var(--color-success-bg);
  border: 1px solid var(--color-success-border);
  border-radius: var(--border-radius-lg);
`;

const SuccessMessageText = styled.div`
  font-size: var(--font-size-base);
  color: var(--color-success-darker);
`;

const ToolCallsInfoWrapper = styled.div`
  display: flex;
  flex-direction: column;
  gap: var(--spacing-xxs);
  margin: 0 0 var(--spacing-sm) 0;
  font-size: var(--font-size-xs);
  color: var(--search-ai-text-color);
  opacity: 0.6;
`;

const ToolCallInfoItem = styled.div`
  display: flex;
  align-items: center;
  gap: var(--spacing-xxs);
`;

const ToolCallText = styled.span<{ $isSearching?: boolean }>`
  font-weight: var(--font-weight-regular);

  ${({ $isSearching }) =>
    $isSearching &&
    `
    animation: pulse 1.5s ease-in-out infinite;
    
    @keyframes pulse {
      0%, 100% {
        opacity: 1;
      }
      50% {
        opacity: 0.4;
      }
    }
  `}
`;
