import React, { useEffect, useRef, useState } from 'react';
import styled from 'styled-components';
import {
  IconButton,
  Tooltip,
  Menu,
  MenuItem,
  Popover,
  Chip,
  TextField,
  Button,
  Stack,
} from '@mui/material';
import ContentCopy from '@mui/icons-material/ContentCopy';
import Check from '@mui/icons-material/Check';
import ThumbUp from '@mui/icons-material/ThumbUp';
import ThumbUpOutlined from '@mui/icons-material/ThumbUpOutlined';
import ThumbDown from '@mui/icons-material/ThumbDown';
import ThumbDownOutlined from '@mui/icons-material/ThumbDownOutlined';
import FileDownload from '@mui/icons-material/FileDownload';
import { copyTextToClipboard } from '../../utils/clipboard';
import { showToast } from '../../utils/toastBus';
import {
  clearPromptFeedback,
  upsertPromptFeedback,
  type PromptRating,
} from '../../utils/promptFeedback';
import {
  exportChat,
  type ExportFormat,
  type ExportTurn,
} from '../../utils/export/exportChat';
import { AnalyticsEvents, trackEvent } from '../../utils/analytics';
import type { Citation } from '../../utils/wsFrames';

const DOWN_REASONS: { code: string; label: string }[] = [
  { code: 'incorrect', label: 'Incorrect' },
  { code: 'out_of_date', label: 'Out of date' },
  { code: 'didnt_follow_instructions', label: "Didn't follow instructions" },
  { code: 'unsafe', label: 'Unsafe' },
  { code: 'other', label: 'Other' },
];

const ActionsRow = styled.div<{ $alwaysVisible: boolean }>`
  display: flex;
  align-items: center;
  gap: 0.15rem;
  margin-top: 0.35rem;
  min-height: 2rem;
  max-width: 100%;
  flex-wrap: wrap;
  opacity: ${({ $alwaysVisible }) => ($alwaysVisible ? 1 : 0)};
  pointer-events: ${({ $alwaysVisible }) => ($alwaysVisible ? 'auto' : 'none')};
  transition: opacity 0.15s ease;

  @media (hover: hover) and (pointer: fine) {
    /* Desktop: revealed via parent :hover / :focus-within when not forced visible */
  }

  @media (hover: none), (pointer: coarse) {
    opacity: 1;
    pointer-events: auto;
  }
`;

const ActionIconButton = styled(IconButton)`
  && {
    color: ${({ theme }) => theme.colors.text};
    opacity: 0.7;
    padding: 0.35rem;

    &:hover,
    &:focus-visible {
      opacity: 1;
      background: ${({ theme }) =>
        theme.darkMode ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.06)'};
    }

    &.Mui-disabled {
      opacity: 0.35;
    }
  }
`;

type MessageActionsProps = {
  promptId?: number;
  rawMarkdown: string;
  userCreated: boolean;
  isStreaming?: boolean;
  isLast?: boolean;
  conversationTitle: string;
  createdTimestamp?: Date | string | null;
  citations?: Citation[];
  initialRating?: PromptRating | null;
  onRatingChange?: (rating: PromptRating | null) => void;
};

const MessageActions = ({
  promptId,
  rawMarkdown,
  userCreated,
  isStreaming = false,
  isLast = false,
  conversationTitle,
  createdTimestamp,
  citations = [],
  initialRating = null,
  onRatingChange,
}: MessageActionsProps): JSX.Element | null => {
  const [copied, setCopied] = useState(false);
  const [rating, setRating] = useState<PromptRating | null>(initialRating);
  const [exportAnchor, setExportAnchor] = useState<null | HTMLElement>(null);
  const [reasonAnchor, setReasonAnchor] = useState<null | HTMLElement>(null);
  const [reasonCode, setReasonCode] = useState<string | null>(null);
  const [reasonComment, setReasonComment] = useState('');
  const [focused, setFocused] = useState(false);
  const copyTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
  const rowRef = useRef<HTMLDivElement | null>(null);

  useEffect(() => {
    setRating(initialRating);
  }, [initialRating, promptId]);

  useEffect(() => {
    return () => {
      if (copyTimer.current) clearTimeout(copyTimer.current);
    };
  }, []);

  if (isStreaming) return null;

  const alwaysVisible = isLast || focused || Boolean(exportAnchor) || Boolean(reasonAnchor);

  const handleCopy = async () => {
    try {
      await copyTextToClipboard(rawMarkdown);
      setCopied(true);
      trackEvent(AnalyticsEvents.MESSAGE_COPIED, {
        role: userCreated ? 'user' : 'assistant',
      });
      if (copyTimer.current) clearTimeout(copyTimer.current);
      copyTimer.current = setTimeout(() => setCopied(false), 2000);
    } catch {
      showToast('Could not copy message', 'error');
    }
  };

  const applyRating = async (next: PromptRating | null) => {
    if (!promptId) {
      showToast('Rating unavailable until message is saved', 'info');
      return;
    }
    const prev = rating;
    setRating(next);
    onRatingChange?.(next);
    try {
      if (next == null) {
        await clearPromptFeedback(promptId);
      } else {
        await upsertPromptFeedback(promptId, { rating: next });
      }
      trackEvent(AnalyticsEvents.MESSAGE_RATED, {
        rating: next ?? 'cleared',
      });
    } catch {
      setRating(prev);
      onRatingChange?.(prev);
      showToast('Could not save rating', 'error');
    }
  };

  const handleThumb = async (
    next: PromptRating,
    event: React.MouseEvent<HTMLElement>,
  ) => {
    if (rating === next) {
      await applyRating(null);
      return;
    }
    await applyRating(next);
    if (next === 'down') {
      setReasonAnchor(event.currentTarget);
      setReasonCode(null);
      setReasonComment('');
    }
  };

  const submitReason = async () => {
    if (!promptId || rating !== 'down') {
      setReasonAnchor(null);
      return;
    }
    try {
      await upsertPromptFeedback(promptId, {
        rating: 'down',
        reason: reasonCode ?? undefined,
        comment: reasonComment.trim() || undefined,
      });
      trackEvent(AnalyticsEvents.MESSAGE_RATING_REASON, {
        reason: reasonCode ?? 'none',
        hasComment: Boolean(reasonComment.trim()),
      });
    } catch {
      showToast('Could not save feedback reason', 'error');
    } finally {
      setReasonAnchor(null);
    }
  };

  const handleExport = async (format: ExportFormat) => {
    setExportAnchor(null);
    const turn: ExportTurn = {
      role: userCreated ? 'user' : 'assistant',
      message: rawMarkdown,
      timestamp: createdTimestamp ?? null,
      citations: userCreated ? [] : citations,
    };
    try {
      await exportChat({
        format,
        scope: 'message',
        title: conversationTitle,
        turns: [turn],
      });
      trackEvent(AnalyticsEvents.MESSAGE_EXPORTED, {
        format,
        scope: 'message',
      });
    } catch (err) {
      console.error(err);
      showToast('Export failed', 'error');
    }
  };

  return (
    <ActionsRow
      ref={rowRef}
      $alwaysVisible={alwaysVisible}
      data-message-actions
      onFocusCapture={() => setFocused(true)}
      onBlurCapture={(e) => {
        if (!rowRef.current?.contains(e.relatedTarget as Node)) {
          setFocused(false);
        }
      }}
    >
      <Tooltip title={copied ? 'Copied' : 'Copy markdown'}>
        <ActionIconButton
          aria-label="Copy message as markdown"
          size="small"
          onClick={() => void handleCopy()}
        >
          {copied ? <Check fontSize="small" /> : <ContentCopy fontSize="small" />}
        </ActionIconButton>
      </Tooltip>

      {!userCreated && (
        <>
          <Tooltip title="Thumbs up">
            <span>
              <ActionIconButton
                aria-label="Thumbs up"
                size="small"
                disabled={!promptId}
                onClick={(e) => void handleThumb('up', e)}
              >
                {rating === 'up' ? (
                  <ThumbUp fontSize="small" />
                ) : (
                  <ThumbUpOutlined fontSize="small" />
                )}
              </ActionIconButton>
            </span>
          </Tooltip>
          <Tooltip title="Thumbs down">
            <span>
              <ActionIconButton
                aria-label="Thumbs down"
                size="small"
                disabled={!promptId}
                onClick={(e) => void handleThumb('down', e)}
              >
                {rating === 'down' ? (
                  <ThumbDown fontSize="small" />
                ) : (
                  <ThumbDownOutlined fontSize="small" />
                )}
              </ActionIconButton>
            </span>
          </Tooltip>
        </>
      )}

      <Tooltip title="Export">
        <ActionIconButton
          aria-label="Export message"
          size="small"
          onClick={(e) => setExportAnchor(e.currentTarget)}
        >
          <FileDownload fontSize="small" />
        </ActionIconButton>
      </Tooltip>

      <Menu
        anchorEl={exportAnchor}
        open={Boolean(exportAnchor)}
        onClose={() => setExportAnchor(null)}
      >
        {(
          [
            ['pdf', 'PDF'],
            ['csv', 'CSV'],
            ['xlsx', 'Excel (.xlsx)'],
            ['txt', 'Plain text'],
          ] as [ExportFormat, string][]
        ).map(([format, label]) => (
          <MenuItem key={format} onClick={() => void handleExport(format)}>
            {label}
          </MenuItem>
        ))}
      </Menu>

      <Popover
        open={Boolean(reasonAnchor)}
        anchorEl={reasonAnchor}
        onClose={() => setReasonAnchor(null)}
        anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}
      >
        <Stack spacing={1.25} sx={{ p: 1.5, width: 280, maxWidth: '90vw' }}>
          <div style={{ fontSize: '0.85rem', fontWeight: 600 }}>
            What went wrong? (optional)
          </div>
          <Stack direction="row" flexWrap="wrap" gap={0.75}>
            {DOWN_REASONS.map((reason) => (
              <Chip
                key={reason.code}
                label={reason.label}
                size="small"
                color={reasonCode === reason.code ? 'primary' : 'default'}
                onClick={() => setReasonCode(reason.code)}
              />
            ))}
          </Stack>
          <TextField
            size="small"
            multiline
            minRows={2}
            placeholder="Additional details (optional)"
            value={reasonComment}
            onChange={(e) => setReasonComment(e.target.value)}
          />
          <Button variant="contained" size="small" onClick={() => void submitReason()}>
            Done
          </Button>
        </Stack>
      </Popover>
    </ActionsRow>
  );
};

export default MessageActions;
