import * as React from 'react';

import type { ColorPaletteProp } from '@mui/joy/styles/types';
import { Box, Chip, Typography } from '@mui/joy';
import AllInclusiveIcon from '@mui/icons-material/AllInclusive';
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
import TextFieldsIcon from '@mui/icons-material/TextFields';

import { RenderMarkdown } from '~/modules/blocks/markdown/RenderMarkdown';
import { useScaledTypographySx } from '~/modules/blocks/blocks.styles';

import { ConfirmationModal } from '~/common/components/modals/ConfirmationModal';
import { ExpanderControlledBox } from '~/common/components/ExpanderControlledBox';
import { adjustContentScaling, ContentScaling } from '~/common/app.theme';
import { animationSpinHalfPause } from '~/common/util/animUtils';
import { createTextContentFragment, DMessageContentFragment, DMessageFragmentId } from '~/common/stores/chat/chat.fragments';
import { useOverlayComponents } from '~/common/layout/overlays/useOverlayComponents';


// configuration
const ENABLE_MARKDOWN_DETECTION = true;
// const REASONING_COLOR = '#ca74b8'; // '#f22a85' (folder-aligned), '#ca74b8' (emoji-aligned)
const REASONING_COLOR: ColorPaletteProp = 'success';
const ANTHROPIC_REDACTED_EXPLAINER = //  https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking#example-streaming-with-redacted-thinking
  'Some of Claude\'s internal reasoning has been automatically encrypted for safety reasons. This doesn\'t affect the quality of responses.';


const _styles = {

  block: {
    mx: 1.5,
  },

  chip: {
    px: 1.5,
    py: 0.375,
    my: '1px', // to not crop the outline on mobile, or on beam
    outline: '1px solid',
    outlineColor: `${REASONING_COLOR}.solidBg`, // .outlinedBorder
    boxShadow: `1px 2px 4px -3px var(--joy-palette-${REASONING_COLOR}-solidBg)`,
  },

  chipDisabled: {
    px: 1.5,
    py: 0.375,
    my: '1px', // to not crop the outline on mobile, or on beam
  },

  chipIcon: {
    fontSize: '1rem',
    mr: 0.5,
  },

  chipIconPending: {
    fontSize: '1rem',
    mr: 0.5,
    animation: `${animationSpinHalfPause} 2s ease-in-out infinite`,
  },

  chipExpanded: {
    mt: '1px', // need to copy the `chip` mt
    px: 1.5,
    py: 0.375,
    // borderRadius: 'sm',
    // transition: 'border-radius 0.2s ease-in-out',
  },

  text: {
    borderRadius: 'sm', // was: 12px
    border: '1px solid',
    borderColor: `${REASONING_COLOR}.outlinedColor`,
    backgroundColor: `rgb(var(--joy-palette-${REASONING_COLOR}-lightChannel) / 15%)`, // similar to success.50
    // boxShadow: 'inset 1px 1px 3px -3px var(--joy-palette-neutral-solidBg)',
    mt: 1,
    p: 1,

    // plain text style
    overflowWrap: 'anywhere',
    whiteSpace: 'break-spaces',

    // layout
    display: 'flex',
    flexDirection: 'column',
  },

  textUndoWhitespace: {
    // for markdown content, we want to allow it to control the whitespace and line breaks, so we undo the plain text styles that break on whitespace
    overflowWrap: 'normal',
    whiteSpace: 'normal',
  },

  buttonInline: {
    outline: 'none',
    // borderRadius: 'sm',
    // fontSize: 'xs',
  },

} as const;


/** Detect if content is potentially markdown based on common markdown patterns */
function _maybeMarkdownReasoning(trimmed: string): boolean {
  // const trimmed = text.trimStart();
  return trimmed.startsWith('**')
    || trimmed.startsWith('# ')
    // || trimmed.startsWith('* ')
    // || trimmed.startsWith('- ')
    || /^#{2,6}\s/.test(trimmed);
}


export function BlockPartModelAux(props: {
  fragmentId: DMessageFragmentId,
  auxType: 'reasoning' | string,
  auxText: string,
  auxHasSignature: boolean,
  auxRedactedDataCount: number,
  messagePendingIncomplete: boolean,
  zenMode: boolean,
  contentScaling: ContentScaling,
  isLastFragment: boolean,
  onFragmentDelete?: (fragmentId: DMessageFragmentId) => void,
  onFragmentReplace?: (fragmentId: DMessageFragmentId, newFragment: DMessageContentFragment) => void,
}) {

  // state
  const [neverExpanded, setNeverExpanded] = React.useState(true);
  const [expanded, setExpanded] = React.useState(false);

  // external state
  const { showPromisedOverlay } = useOverlayComponents();

  // memo
  const scaledTypographySx = useScaledTypographySx(adjustContentScaling(props.contentScaling, -1), false, false);
  const maybeMarkdown = React.useMemo(() => !ENABLE_MARKDOWN_DETECTION || neverExpanded ? false : _maybeMarkdownReasoning(props.auxText), [neverExpanded, props.auxText]);
  const textSx = React.useMemo(() => ({
    ..._styles.text,
    ...scaledTypographySx,
    ...(maybeMarkdown ? _styles.textUndoWhitespace : {}),
  }), [maybeMarkdown, scaledTypographySx]);

  let typeText = props.auxType === 'reasoning' ? 'Reasoning' : 'Auxiliary';


  // handlers

  const { onFragmentDelete, onFragmentReplace } = props;
  const showDelete = !!onFragmentDelete;
  const showInline = !!onFragmentReplace;

  const handleToggleExpanded = React.useCallback(() => {
    setNeverExpanded(false);
    setExpanded(on => !on);
  }, []);

  const handleDelete = React.useCallback(() => {
    if (!onFragmentDelete) return;
    showPromisedOverlay('chat-message-delete-aux', {}, ({ onResolve, onUserReject }) =>
      <ConfirmationModal
        open onClose={onUserReject} onPositive={() => onResolve(true)}
        confirmationText={<>
          Delete this {typeText.toLowerCase()} completely?
          <br />
          This action cannot be undone.
        </>}
        positiveActionText='Delete'
      />,
    ).then(() => {
      onFragmentDelete(props.fragmentId);
    }).catch(() => null /* ignore closure */);
  }, [onFragmentDelete, props.fragmentId, showPromisedOverlay, typeText]);

  const handleInline = React.useCallback(() => {
    if (!onFragmentReplace) return;
    showPromisedOverlay('chat-message-inline-aux', {}, ({ onResolve, onUserReject }) =>
      <ConfirmationModal
        open onClose={onUserReject} onPositive={() => onResolve(true)}
        confirmationText={<>
          Convert this {typeText.toLowerCase()} into regular message text?
          <br />
          It will become part of the message and can&apos;t be collapsed again.
        </>}
        positiveActionText='Convert'
      />,
    ).then(() => {
      onFragmentReplace(props.fragmentId, createTextContentFragment(props.auxText));
    }).catch(() => null /* ignore closure */);
  }, [onFragmentReplace, props.auxText, props.fragmentId, showPromisedOverlay, typeText]);


  // create up to 3 dots '.' based on the length of the auxText (1 dot per 100 characters)
  // const dots = '.'.repeat(Math.floor(props.auxText.length / 100) % 5);

  return <Box sx={_styles.block}>

    {/* Chip to expand/collapse */}
    <Box data-agi-no-copy /* do not copy these buttons */ sx={{ display: 'flex', flexWrap: 'wrap', gap: 1, alignItems: 'center', justifyContent: 'space-between' }}>
      <Chip
        color={props.isLastFragment ? REASONING_COLOR : 'neutral'}
        variant={expanded ? 'solid' : 'soft'}
        size='sm'
        onClick={handleToggleExpanded}
        sx={expanded ? _styles.chipExpanded : props.isLastFragment ? _styles.chip : _styles.chipDisabled}
        startDecorator={
          <AllInclusiveIcon
            sx={(props.messagePendingIncomplete && !expanded && props.isLastFragment) ? _styles.chipIconPending : _styles.chipIcon}
            /* sx={{ color: expanded ? undefined : REASONING_COLOR }} */
          />
        }
        // startDecorator='🧠'
      >
        Show {typeText}
      </Chip>

      {expanded && !props.messagePendingIncomplete && (showInline || showDelete) && !!props.auxText && (
        <Box sx={{ display: 'flex', gap: 1 }}>

          {/* Make inline */}
          {showInline && <Chip
            color={REASONING_COLOR}
            variant='soft'
            size='sm'
            disabled={!onFragmentReplace /* || props.messagePendingIncomplete */}
            onClick={!onFragmentReplace ? undefined : handleInline}
            endDecorator={<TextFieldsIcon />}
            sx={(!onFragmentReplace /* || props.messagePendingIncomplete */) ? _styles.chipDisabled : _styles.chip}
          >
            Make Regular Text
          </Chip>}

          {/* Delete */}
          {showDelete && <Chip
            color={REASONING_COLOR}
            variant='soft'
            size='sm'
            disabled={!onFragmentDelete /* || props.messagePendingIncomplete */}
            onClick={!onFragmentDelete ? undefined : handleDelete}
            endDecorator={<DeleteOutlineIcon />}
            sx={(!onFragmentDelete /* || props.messagePendingIncomplete */) ? _styles.chipDisabled : _styles.chip}
          >
            Delete
          </Chip>}

        </Box>
      )}
    </Box>

    {/* Controlled Box */}
    <ExpanderControlledBox expanded={expanded}>

      {!neverExpanded && (
        (ENABLE_MARKDOWN_DETECTION && maybeMarkdown) ? (
          <Box sx={textSx}>
            <RenderMarkdown content={props.auxText} sx={{ ...scaledTypographySx, marginInline: '0!important' /* to override what's default in this component */ }} />
            {!!props.auxRedactedDataCount && <Box component='span' sx={{ color: 'text.disabled' }}> {ANTHROPIC_REDACTED_EXPLAINER}{'.'.repeat(props.auxRedactedDataCount % 5)}</Box>}
          </Box>
        ) : (
          <Typography sx={textSx}>
            <span>
              {props.auxText}
              {!!props.auxRedactedDataCount && <Box component='span' sx={{ color: 'text.disabled' }}> {ANTHROPIC_REDACTED_EXPLAINER}{'.'.repeat(props.auxRedactedDataCount % 5)}</Box>}
            </span>
          </Typography>
        )
      )}

    </ExpanderControlledBox>

  </Box>;
}