import { css } from '@emotion/css';
import { useState, useCallback } from 'react';

import { GrafanaTheme2 } from '@grafana/data';
import { Alert, Button, Icon, Input, Stack, Text, TextLink, useStyles2 } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';

import { STOP_GENERATION_TEXT } from './GenAIButton';
import { GenerationHistoryCarousel } from './GenerationHistoryCarousel';
import { QuickFeedback } from './QuickFeedback';
import { StreamStatus, useOpenAIStream } from './hooks';
import { AutoGenerateItem, EventTrackingSrc, reportAutoGenerateInteraction } from './tracking';
import { getFeedbackMessage, Message, DEFAULT_OAI_MODEL, QuickFeedbackType, sanitizeReply } from './utils';

export interface GenAIHistoryProps {
  history: string[];
  messages: Message[];
  onApplySuggestion: (suggestion: string) => void;
  updateHistory: (historyEntry: string) => void;
  eventTrackingSrc: EventTrackingSrc;
}

const temperature = 0.5;

export const GenAIHistory = ({
  eventTrackingSrc,
  history,
  messages,
  onApplySuggestion,
  updateHistory,
}: GenAIHistoryProps) => {
  const styles = useStyles2(getStyles);

  const [currentIndex, setCurrentIndex] = useState(1);
  const [customFeedback, setCustomPrompt] = useState('');

  const onResponse = useCallback(
    (response: string) => {
      updateHistory(sanitizeReply(response));
    },
    [updateHistory]
  );

  const { setMessages, stopGeneration, reply, streamStatus, error } = useOpenAIStream({
    model: DEFAULT_OAI_MODEL,
    temperature,
    onResponse,
  });

  const reportInteraction = (item: AutoGenerateItem, otherMetadata?: object) =>
    reportAutoGenerateInteraction(eventTrackingSrc, item, otherMetadata);

  const onSubmitCustomFeedback = (text: string) => {
    onGenerateWithFeedback(text);
    reportInteraction(AutoGenerateItem.customFeedback, { customFeedback: text });
  };

  const onStopGeneration = () => {
    stopGeneration();
    reply && onResponse(reply);
  };

  const onApply = () => {
    onApplySuggestion(history[currentIndex - 1]);
  };

  const onNavigate = (index: number) => {
    setCurrentIndex(index);
    reportInteraction(index > currentIndex ? AutoGenerateItem.backHistoryItem : AutoGenerateItem.forwardHistoryItem);
  };

  const onGenerateWithFeedback = (suggestion: string) => {
    setMessages((messages) => [...messages, ...getFeedbackMessage(history[currentIndex - 1], suggestion)]);

    if (suggestion in QuickFeedbackType) {
      reportInteraction(AutoGenerateItem.quickFeedback, { quickFeedbackItem: suggestion });
    }
  };

  const onKeyDownCustomFeedbackInput = (e: React.KeyboardEvent<HTMLInputElement>) =>
    e.key === 'Enter' && onSubmitCustomFeedback(customFeedback);

  const onChangeCustomFeedback = (e: React.FormEvent<HTMLInputElement>) => setCustomPrompt(e.currentTarget.value);

  const onClickSubmitCustomFeedback = () => onSubmitCustomFeedback(customFeedback);

  const onClickDocs = () => reportInteraction(AutoGenerateItem.linkToDocs);

  const isStreamGenerating = streamStatus === StreamStatus.GENERATING;
  const showError = error && !isStreamGenerating;

  return (
    <div className={styles.container}>
      {showError && (
        <Alert title="">
          <Stack direction="column">
            <p>
              <Trans i18nKey="gen-ai.incomplete-request-error">
                Sorry, I was unable to complete your request. Please try again.
              </Trans>
            </p>
          </Stack>
        </Alert>
      )}

      <GenerationHistoryCarousel history={history} index={currentIndex} onNavigate={onNavigate} />

      <div className={styles.actionButtons}>
        <QuickFeedback onSuggestionClick={onGenerateWithFeedback} isGenerating={isStreamGenerating} />
      </div>

      <Input
        placeholder="Tell AI what to do next..."
        suffix={
          <Button
            icon="enter"
            variant="secondary"
            fill="text"
            aria-label="Send custom feedback"
            onClick={onClickSubmitCustomFeedback}
            disabled={!customFeedback}
          >
            <Trans i18nKey="gen-ai.send-custom-feedback">Send</Trans>
          </Button>
        }
        value={customFeedback}
        onChange={onChangeCustomFeedback}
        onKeyDown={onKeyDownCustomFeedbackInput}
      />

      <div className={styles.applySuggestion}>
        <Stack justifyContent="flex-end" direction="row">
          {isStreamGenerating ? (
            <Button icon="fa fa-spinner" onClick={onStopGeneration}>
              {STOP_GENERATION_TEXT}
            </Button>
          ) : (
            <Button icon="check" onClick={onApply}>
              <Trans i18nKey="gen-ai.apply-suggestion">Apply</Trans>
            </Button>
          )}
        </Stack>
      </div>

      <div className={styles.footer}>
        <Icon name="exclamation-circle" aria-label="exclamation-circle" className={styles.infoColor} />
        <Text variant="bodySmall" color="secondary">
          This content is AI-generated using the{' '}
          <TextLink
            variant="bodySmall"
            inline={true}
            href="https://grafana.com/docs/grafana-cloud/alerting-and-irm/machine-learning/llm-plugin/"
            external
            onClick={onClickDocs}
          >
            Grafana LLM plugin
          </TextLink>
        </Text>
      </div>
    </div>
  );
};

const getStyles = (theme: GrafanaTheme2) => ({
  container: css({
    display: 'flex',
    flexDirection: 'column',
    width: 520,
    maxHeight: 350,
    // This is the space the footer height
    paddingBottom: 25,
  }),
  applySuggestion: css({
    paddingTop: theme.spacing(2),
  }),
  actions: css({
    display: 'flex',
    flexDirection: 'row',
    flexWrap: 'wrap',
  }),
  footer: css({
    // Absolute positioned since Toggletip doesn't support footer
    position: 'absolute',
    bottom: 0,
    left: 0,
    width: '100%',
    display: 'flex',
    flexDirection: 'row',
    margin: 0,
    padding: theme.spacing(1),
    paddingLeft: theme.spacing(2),
    alignItems: 'center',
    gap: theme.spacing(1),
    borderTop: `1px solid ${theme.colors.border.weak}`,
    marginTop: theme.spacing(2),
  }),
  infoColor: css({
    color: theme.colors.info.main,
  }),
  actionButtons: css({
    display: 'flex',
    flexDirection: 'row',
    justifyContent: 'space-between',
    padding: '24px 0 8px 0',
  }),
});
