import styled from '@emotion/styled';
import clsx from 'clsx';
import React, {
  RefObject,
  useCallback,
  useEffect,
  useRef,
  useState,
} from 'react';

import Button, {
  ButtonShape,
  ButtonSize,
  ButtonVariant,
} from '@/components/button/Button';
import SpinnerSVG from '@/components/svg/SpinnerSVG';

import { OrpheusReferenceIcon } from '../../OrpheusReferenceIcon';
import { useChatContext } from '../../useChat';
import { AddReferencePayload, ReferenceType } from '../input/ReferenceTypes';
import { ShimmerLines } from './ShimmerLines';

type SendToChatButtonProps = {
  onSendToChatClick: () => void;
  rangeOffsetTop: number;
  rangeOffsetLeft: number;
};

const SendToChatButtonContainer = styled.div<{
  rangeOffsetTop: number;
  rangeOffsetLeft: number;
}>`
  position: absolute;
  background-color: black;
  z-index: 5000;
  top: ${(props) => props.rangeOffsetTop}px;
  left: ${(props) => props.rangeOffsetLeft}px;
  height: auto;
  width: auto;
`;

const TextContainer = styled.div`
  position: relative;
  height: auto;
  width: 100%;

  textarea {
    ::selection {
      background-color: rgb(var(--rgb-background-fog-thick) / 10%);
    }
  }
`;

const SendToChatButton = ({
  onSendToChatClick,
  rangeOffsetTop,
  rangeOffsetLeft,
}: SendToChatButtonProps) => {
  return (
    <SendToChatButtonContainer
      rangeOffsetTop={rangeOffsetTop}
      rangeOffsetLeft={rangeOffsetLeft}
      className='rounded-full'
    >
      <Button
        iconStart={OrpheusReferenceIcon}
        variant={ButtonVariant.Aura}
        shape={ButtonShape.Pill}
        size={ButtonSize.Small}
        onClick={(e) => {
          onSendToChatClick();
          e.stopPropagation();
        }}
        className='send-to-chat-button'
      >
        Send to chat
      </Button>
    </SendToChatButtonContainer>
  );
};

export const StylesLyricsCard = ({
  styles,
  lyrics,
  // title,
  // toolCallId,
  onAllowChildScroll,
  showStylesLyrics = false, // override to always show both styles and lyrics boxes
  isLoading = false,
  isStreaming = false,
}: {
  styles?: string;
  lyrics?: string;
  lyricsVersion?: number;
  stylesVersion?: number;
  title?: string;
  toolCallId?: string;
  onAllowChildScroll: () => void;
  showStylesLyrics?: boolean;
  isLoading?: boolean;
  isStreaming?: boolean;
}) => {
  const { addReference } = useChatContext();
  const referenceLyricsRef = useRef<HTMLTextAreaElement>(null);
  const referenceStylesRef = useRef<HTMLTextAreaElement>(null);
  const referenceLyricsWrapperRef = useRef<HTMLDivElement>(null);
  const [isLyricsExpanded, setIsLyricsExpanded] = useState(false);
  const [pendingReference, setPendingReference] =
    useState<AddReferencePayload | null>(null);
  const [rangeOffset, setRangeOffset] = useState<{
    top: number;
    left: number;
  } | null>(null);
  const mirrorDiv = useRef<HTMLDivElement | null>(null);

  const getSelectionCoords = useCallback(
    (textArea: HTMLTextAreaElement | null) => {
      if (!textArea) return;
      if (!mirrorDiv.current) {
        mirrorDiv.current = document.createElement('div');
        mirrorDiv.current.style.position = 'absolute';
        mirrorDiv.current.style.whiteSpace = 'pre-wrap';
        mirrorDiv.current.style.visibility = 'hidden';
        mirrorDiv.current.style.pointerEvents = 'none';
        mirrorDiv.current.style.top = '0px';
        mirrorDiv.current.style.left = '0px';
        textArea.parentElement?.appendChild(mirrorDiv.current);
      }

      const computed = window.getComputedStyle(textArea);
      mirrorDiv.current.style.font = computed.font;
      mirrorDiv.current.style.padding = computed.padding;
      mirrorDiv.current.style.width = computed.width;
      mirrorDiv.current.style.lineHeight = computed.lineHeight;
      mirrorDiv.current.style.letterSpacing = computed.letterSpacing;

      const start = textArea.selectionStart;
      const textBefore = textArea.value.substring(0, start);
      mirrorDiv.current.textContent = textBefore;
      const span = document.createElement('span');
      span.style.visibility = 'hidden';
      span.textContent = '|';
      mirrorDiv.current.appendChild(span);
      const textareaRect = textArea.getBoundingClientRect();
      const spanRect = span.getBoundingClientRect();

      return {
        top: spanRect.top - textareaRect.top + textArea.scrollTop,
        left: spanRect.left - textareaRect.left + textArea.scrollLeft,
        height: spanRect.height,
      };
    },
    [mirrorDiv]
  );

  const handleSelection = useCallback(
    (
      textAreaRef: RefObject<HTMLTextAreaElement | null>,
      referenceType: ReferenceType,
      shouldClear?: boolean
    ) => {
      if (
        ![ReferenceType.LYRICS, ReferenceType.STYLES].includes(referenceType)
      ) {
        return;
      }

      const textArea = textAreaRef.current;
      const selectionCoords = getSelectionCoords(textArea);

      if (
        textArea?.selectionStart === undefined ||
        textArea?.selectionEnd === undefined ||
        textArea?.selectionStart === textArea?.selectionEnd ||
        shouldClear
      ) {
        setTimeout(() => {
          setPendingReference(null);
          setRangeOffset(null);
        }, 100);
        return;
      }

      const text = textArea?.value || '';
      const startOffset = textArea?.selectionStart ?? 0;
      const endOffset = textArea?.selectionEnd ?? 0;
      const BUTTON_OFFSET_TOP = 50; // Height adjustment for "Send to chat" button positioning
      if (
        startOffset >= 0 &&
        endOffset <= text.length &&
        startOffset < endOffset
      ) {
        const addReferencePayload: AddReferencePayload =
          referenceType === ReferenceType.LYRICS
            ? {
                type: ReferenceType.LYRICS,
                lyrics: {
                  message: text,
                  selectionOverlayRange: {
                    start: startOffset,
                    end: endOffset,
                  },
                  toolCallId: null,
                },
              }
            : {
                type: ReferenceType.STYLES,
                styles: {
                  message: text,
                  selectionOverlayRange: {
                    start: startOffset,
                    end: endOffset,
                  },
                  toolCallId: null,
                },
              };
        setPendingReference(addReferencePayload);
        setRangeOffset({
          top: Math.max(0, (selectionCoords?.top ?? 0) - BUTTON_OFFSET_TOP),
          left: selectionCoords?.left ?? 0,
        });
      }
    },
    [setPendingReference, setRangeOffset, getSelectionCoords]
  );

  const handleSelectLyrics = useCallback(() => {
    handleSelection(referenceLyricsRef, ReferenceType.LYRICS);
  }, [handleSelection, referenceLyricsRef]);

  const handleSelectStyles = useCallback(() => {
    handleSelection(referenceStylesRef, ReferenceType.STYLES);
  }, [handleSelection, referenceStylesRef]);

  const handleSendToChatClick = useCallback(() => {
    if (pendingReference) {
      addReference(pendingReference);
      setPendingReference(null);
      setRangeOffset(null);
    }
  }, [setPendingReference, setRangeOffset, addReference, pendingReference]);

  // const handleEditClick = useCallback(() => {
  //   setEditingContext({
  //     styles: styles ?? null,
  //     lyrics: lyrics ?? null,
  //     title: title,
  //     toolCallId: toolCallId,
  //   });
  //   setIsEditingModalOpen(true);
  // }, [
  //   styles,
  //   lyrics,
  //   title,
  //   setIsEditingModalOpen,
  //   setEditingContext,
  //   toolCallId,
  // ]);

  useEffect(() => {
    if (isLoading) {
      return; // avoid resizing while shimmer placeholders are showing
    }

    const lyricsEl = referenceLyricsRef.current;
    const stylesEl = referenceStylesRef.current;

    if (lyricsEl) {
      // Temporarily disable transitions to measure content height
      const hadTransition = lyricsEl.style.transition;

      // Width control needed to avoid element resizing to wrong height
      const width =
        lyricsEl.offsetWidth || lyricsEl.parentElement?.clientWidth || 368;
      lyricsEl.style.width = `${width}px`;
      lyricsEl.style.transition = 'none';
      const newHeight = lyricsEl.scrollHeight;

      // Force reflow
      void lyricsEl.offsetHeight;

      // Re-enable transitions before setting the new height
      requestAnimationFrame(() => {
        lyricsEl.style.transition = hadTransition || 'height 0.2s ease-out';
        lyricsEl.style.height = `${newHeight}px`;
      });
    }

    if (stylesEl) {
      const hadTransition = stylesEl.style.transition;

      // Width control needed to avoid element resizing to wrong height
      const width =
        stylesEl.offsetWidth || stylesEl.parentElement?.clientWidth || 368;
      stylesEl.style.width = `${width}px`;
      stylesEl.style.transition = 'none';
      const newHeight = stylesEl.scrollHeight;

      // Force reflow
      void stylesEl.offsetHeight;

      requestAnimationFrame(() => {
        stylesEl.style.transition = hadTransition || 'height 0.2s ease-out';
        stylesEl.style.height = `${newHeight}px`;
      });
    }
  }, [styles, lyrics, isLoading, isStreaming]);

  useEffect(() => {
    return () => {
      if (mirrorDiv.current) {
        mirrorDiv.current.remove();
        mirrorDiv.current = null;
      }
    };
  }, []);

  if (!styles && !lyrics && !showStylesLyrics && !isLoading) return null;

  return (
    <div className='h-auto w-[400px] max-w-full rounded-2xl bg-background-fog-thin p-4 whitespace-pre-wrap'>
      {styles || showStylesLyrics || isLoading ? (
        <>
          <div className='flex h-auto items-center justify-between'>
            <h3 className='pb-4 font-medium text-foreground-primary'>Styles</h3>
            <div className='flex'>
              {/*!!stylesVersion && session.isStaff ? (
                  <div className='flex items-center rounded-full bg-background-fog-thick px-3 py-0 text-xs font-semibold'>
                    v{stylesVersion}
                  </div>
                ) : null*/}
              {isLoading ? null : (
                <Button
                  onClick={() => {
                    // if (
                    //   !toolCallId ||
                    //   styles === undefined ||
                    //   lyrics === undefined ||
                    //   !session.isStaff
                    // ) {
                    //   addReference({
                    //     type: ReferenceType.STYLES,
                    //     styles: {
                    //       message: styles || '',
                    //       toolCallId: null,
                    //     },
                    //   });
                    // } else {
                    //   handleEditClick();
                    // }
                    addReference({
                      type: ReferenceType.STYLES,
                      styles: {
                        message: styles || '',
                        toolCallId: null,
                      },
                    });
                  }}
                  icon={
                    // toolCallId &&
                    // styles !== undefined &&
                    // lyrics !== undefined &&
                    // session.isStaff
                    //   ? EditIcon
                    //   : OrpheusReferenceIcon
                    OrpheusReferenceIcon
                  }
                  shape={ButtonShape.Pill}
                  size={ButtonSize.Mini}
                  variant={ButtonVariant.Tertiary}
                />
              )}
            </div>
          </div>
          <div className='styles-container h-auto w-full'>
            {isLoading ? (
              <ShimmerLines widths={[328, 212]} />
            ) : (
              <TextContainer>
                {pendingReference?.type === ReferenceType.STYLES &&
                rangeOffset !== null ? (
                  <SendToChatButton
                    onSendToChatClick={handleSendToChatClick}
                    rangeOffsetTop={rangeOffset.top}
                    rangeOffsetLeft={0}
                  />
                ) : null}
                <textarea
                  ref={referenceStylesRef}
                  className='w-full resize-none text-sm leading-[24px] text-foreground-secondary outline-none'
                  value={styles ?? '(No styles)'}
                  readOnly
                  suppressContentEditableWarning={true}
                  onSelectCapture={(e) => {
                    requestAnimationFrame(() => handleSelectStyles());
                    e.stopPropagation();
                  }}
                  onBlur={() => {
                    handleSelection(
                      referenceStylesRef,
                      ReferenceType.STYLES,
                      true
                    );
                  }}
                  onMouseUp={() => {
                    requestAnimationFrame(() => handleSelectStyles());
                  }}
                  style={{
                    userSelect: 'text',
                    whiteSpace: 'pre-wrap',
                    minHeight: '1em',
                  }}
                />
              </TextContainer>
            )}
          </div>
        </>
      ) : null}
      {(styles && lyrics) || showStylesLyrics || isLoading ? (
        <hr className='my-4 border-background-fog-thick' />
      ) : null}
      {lyrics || showStylesLyrics || isLoading ? (
        <>
          <div className='flex h-auto items-center justify-between'>
            <h3 className='pb-4 font-medium text-foreground-primary'>Lyrics</h3>
            <div className='flex'>
              {/*!!lyricsVersion && session.isStaff ? (
                  <div className='flex items-center rounded-full bg-background-fog-thick px-3 py-0 text-xs font-semibold'>
                    v{lyricsVersion}
                  </div>
                ) : null*/}
              {isLoading ? null : (
                <Button
                  onClick={() => {
                    // if (
                    //   !toolCallId ||
                    //   styles === undefined ||
                    //   lyrics === undefined ||
                    //   !session.isStaff
                    // ) {
                    //   addReference({
                    //     type: ReferenceType.LYRICS,
                    //     lyrics: {
                    //       message: lyrics || '',
                    //       selectionOverlayRange: {
                    //         start: 0,
                    //         end: lyrics?.length || 0,
                    //       },
                    //       toolCallId: null,
                    //     },
                    //   });
                    // } else {
                    //   handleEditClick();
                    // }
                    addReference({
                      type: ReferenceType.LYRICS,
                      lyrics: {
                        message: lyrics || '',
                        selectionOverlayRange: {
                          start: 0,
                          end: lyrics?.length || 0,
                        },
                        toolCallId: null,
                      },
                    });
                  }}
                  icon={
                    // toolCallId &&
                    // styles !== undefined &&
                    // lyrics !== undefined &&
                    // session.isStaff
                    //   ? EditIcon
                    //   : OrpheusReferenceIcon
                    OrpheusReferenceIcon
                  }
                  shape={ButtonShape.Pill}
                  size={ButtonSize.Mini}
                  variant={ButtonVariant.Tertiary}
                />
              )}
            </div>
          </div>
          <div
            className={clsx('lyrics-container h-auto overflow-y-hidden', {
              'max-h-[8lh]': !isLyricsExpanded,
            })}
            ref={referenceLyricsWrapperRef}
          >
            {isLoading ? (
              <ShimmerLines
                widths={[104, 294, 294, 294, 294, 294, 294, 239, 239, 190]}
              />
            ) : (
              <TextContainer>
                {pendingReference?.type === ReferenceType.LYRICS &&
                rangeOffset !== null ? (
                  <SendToChatButton
                    onSendToChatClick={handleSendToChatClick}
                    rangeOffsetTop={rangeOffset.top}
                    rangeOffsetLeft={rangeOffset.left}
                  />
                ) : null}
                <textarea
                  ref={referenceLyricsRef}
                  className='h-auto w-full cursor-text resize-none text-sm leading-[24px] text-foreground-secondary outline-none'
                  aria-label='Select lyrics text to send to chat'
                  readOnly
                  onSelectCapture={(e) => {
                    requestAnimationFrame(() => handleSelectLyrics());
                    e.stopPropagation();
                  }}
                  onBlur={(e) => {
                    if (e.target.matches('.send-to-chat-button *')) {
                      return;
                    }
                    handleSelection(
                      referenceLyricsRef,
                      ReferenceType.LYRICS,
                      true
                    );
                  }}
                  onMouseUp={() => {
                    requestAnimationFrame(() => handleSelectLyrics());
                  }}
                  style={{
                    userSelect: 'text',
                    whiteSpace: 'pre-wrap',
                    minHeight: '1em',
                  }}
                  value={lyrics || '(Instrumental)'}
                />
              </TextContainer>
            )}
          </div>
          {isLoading ? null : (
            <div className='mt-4 flex w-full items-center justify-between'>
              <Button
                className='bg-transparent p-0 font-medium text-accent-pink'
                onClick={() => {
                  onAllowChildScroll?.();
                  setIsLyricsExpanded((prev) => !prev);
                }}
              >
                {isLyricsExpanded ? 'See less' : 'See more'}
              </Button>
              {isStreaming ? (
                <span className='flex gap-2'>
                  <SpinnerSVG className='text-foreground-tertiary' />
                  <span className='text-sm text-foreground-tertiary'>
                    Writing
                  </span>
                </span>
              ) : null}
            </div>
          )}
        </>
      ) : null}
    </div>
  );
};
