import {
  type ComponentProps,
  type KeyboardEvent,
  useEffect,
  useState,
} from 'react';
import { useTranslation } from 'react-i18next';

import FileIcon from '@composed-components/files/FileIcon';
import ImagePreviewDialog from '@composed-components/files/ImagePreviewDialog';
import Avatar from '@design-system/Avatar';
import CardContainer from '@design-system/CardContainer';
import Title from '@design-system/Title';
import {
  Box,
  IconButton,
  LinearProgress,
  Stack,
  useTheme,
} from '@mui/material';
import {
  IconAlertTriangle,
  IconCheck,
  IconDownload,
  IconExchange,
  IconFile,
  IconTrash,
  IconX,
} from '@tabler/icons-react';
import { bytesToSize } from '@utils/bytes';
import { downloadFile, downloadUrl, getFileExtension } from '@utils/files';

import { type FileCardProps } from './types';

const FileCard = ({
  status,
  sx,
  onRemove,
  onReupload,
  file,
  attachment,
  fileAsset,
  showDownloadButton = true,
  showReuploadButton = true,
  showRemoveButton = true,
  showRemoveUploadingButton = true,
  disabled = false,
  readOnly = false,
  useFileIcon = false,
}: FileCardProps) => {
  const theme = useTheme();
  const { t } = useTranslation('material_hu_only');
  let Icon = null;
  let iconColor: ComponentProps<typeof Avatar>['color'] = 'primary';
  let description = '';
  let descriptionColor = null;
  let showRemove = showRemoveButton;
  let RemoveIcon = IconTrash;
  let ReuploadIcon = null;
  let DownloadIcon = null;
  let cardProps = {};

  const finalFile = file || attachment || fileAsset!;

  // Get size string - fileAsset.size is already formatted, file.size needs conversion
  const getSize = () => {
    if (fileAsset) return fileAsset.size;
    if (attachment) return attachment.size;
    if (file) return bytesToSize(file.size);
    return '';
  };

  // Object URL for native File previews; tracked so we can revoke it on cleanup.
  const [nativeFilePreviewUrl, setNativeFilePreviewUrl] = useState<
    string | null
  >(null);

  useEffect(() => {
    if (!useFileIcon || !file || !file.type?.startsWith('image/')) {
      setNativeFilePreviewUrl(null);
      return undefined;
    }
    const url = URL.createObjectURL(file);
    setNativeFilePreviewUrl(url);
    return () => URL.revokeObjectURL(url);
  }, [useFileIcon, file]);

  // Thumbnail for the small FileIcon slot; prefers the lighter `thumbnailUrl`
  // when the asset provides one.
  const getThumbnailUrl = (): string | undefined => {
    if (!useFileIcon) return undefined;
    if (fileAsset?.type === 'IMAGE') {
      return fileAsset.thumbnailUrl ?? fileAsset.url;
    }
    if (attachment?.type?.startsWith('image/')) {
      return attachment.url;
    }
    return nativeFilePreviewUrl ?? undefined;
  };

  // Full-resolution source for the preview dialog; always uses the original
  // asset url so the dialog never renders a downscaled thumbnail.
  const getFullPreviewUrl = (): string | undefined => {
    if (!useFileIcon) return undefined;
    if (fileAsset?.type === 'IMAGE') {
      return fileAsset.url;
    }
    if (attachment?.type?.startsWith('image/')) {
      return attachment.url;
    }
    return nativeFilePreviewUrl ?? undefined;
  };

  const thumbnailUrl = getThumbnailUrl();
  const fullPreviewUrl = getFullPreviewUrl();
  const canPreviewImage = Boolean(fullPreviewUrl) && !disabled;

  const [isPreviewOpen, setIsPreviewOpen] = useState(false);

  // Force the dialog closed if the card stops being previewable while it is
  // open, so it doesn't auto-reopen when previewability comes back.
  useEffect(() => {
    if (!canPreviewImage && isPreviewOpen) {
      setIsPreviewOpen(false);
    }
  }, [canPreviewImage, isPreviewOpen]);

  const handleOpenPreview = () => setIsPreviewOpen(true);
  const handleClosePreview = () => setIsPreviewOpen(false);

  // Keyboard activation for the inline preview trigger so the filename behaves
  // like a button (Enter / Space) for non-pointer users.
  const handlePreviewKeyDown = (event: KeyboardEvent<HTMLSpanElement>) => {
    if (event.key === 'Enter' || event.key === ' ') {
      event.preventDefault();
      handleOpenPreview();
    }
  };

  const handleDownloadFromPreview = () => {
    if (file) {
      downloadFile(file);
      return;
    }
    const asset = attachment || fileAsset;
    if (asset?.url) {
      downloadUrl(asset.url, asset.name);
    }
  };

  switch (status) {
    case 'default':
      Icon = IconFile;
      description = `${getSize()} • ${(getFileExtension(finalFile?.name ?? '') ?? '').toUpperCase()}`;
      DownloadIcon = IconDownload;
      break;
    case 'success':
      Icon = IconCheck;
      description = `${getSize()} • ${(getFileExtension(finalFile?.name ?? '') ?? '').toUpperCase()}`;
      DownloadIcon = IconDownload;
      break;
    case 'uploading':
      Icon = IconFile;
      description = `${getSize()} • ${t('hu_file_card.loading')}...`;
      RemoveIcon = IconX;
      showRemove = showRemoveUploadingButton;
      break;
    case 'error':
      Icon = IconAlertTriangle;
      ReuploadIcon = IconExchange;
      iconColor = 'error';
      cardProps = {
        backgroundColor: theme.palette.new.background.feedback.error,
        borderColor: theme.palette.new.border.states.error,
      };
      description = t('hu_file_card.loading_error');
      descriptionColor = theme.palette.new.text.feedback.error;
      break;
  }

  return (
    <CardContainer sx={{ ...cardProps, ...sx }}>
      <Stack
        sx={{
          flexDirection: 'row',
          gap: 1,
        }}
      >
        {useFileIcon ? (
          <FileIcon
            size="medium"
            file={{
              extension: getFileExtension(finalFile?.name ?? ''),
            }}
            src={thumbnailUrl}
            alt={finalFile?.name}
          />
        ) : (
          <Avatar
            color={iconColor}
            size="medium"
            Icon={Icon}
          />
        )}
        <Title
          variant="S"
          title={
            <Box
              component="span"
              title={finalFile.name}
              role={canPreviewImage ? 'button' : undefined}
              tabIndex={canPreviewImage ? 0 : undefined}
              onClick={canPreviewImage ? handleOpenPreview : undefined}
              onKeyDown={canPreviewImage ? handlePreviewKeyDown : undefined}
              sx={
                canPreviewImage
                  ? {
                      cursor: 'pointer',
                      '&:hover': { textDecoration: 'underline' },
                      '&:focus-visible': {
                        outline: `2px solid ${theme.palette.primary.main}`,
                        outlineOffset: 2,
                        borderRadius: 1,
                      },
                    }
                  : undefined
              }
            >
              {finalFile.name}
            </Box>
          }
          description={description}
          withEllipsis
          sx={{
            flex: 1,
            minWidth: 0,
            wordBreak: 'break-all',
            '.MuiTypography-globalXS': {
              color: descriptionColor,
            },
          }}
        />
        {ReuploadIcon && onReupload && showReuploadButton && (
          <IconButton
            onClick={onReupload}
            disabled={disabled}
          >
            <ReuploadIcon size={24} />
          </IconButton>
        )}
        {DownloadIcon && showDownloadButton && (
          <IconButton
            onClick={() => {
              if (file) {
                downloadFile(file);
              } else {
                const asset = attachment || fileAsset!;
                downloadUrl(asset.url, asset.name);
              }
            }}
            disabled={disabled}
          >
            <DownloadIcon size={24} />
          </IconButton>
        )}
        {onRemove && showRemove && !readOnly && (
          <IconButton
            onClick={onRemove}
            disabled={disabled}
          >
            <RemoveIcon size={24} />
          </IconButton>
        )}
      </Stack>
      {status === 'uploading' && (
        <LinearProgress
          sx={{ mt: 2, borderRadius: 1 }}
          variant="indeterminate"
        />
      )}
      {canPreviewImage && (
        <ImagePreviewDialog
          open={isPreviewOpen}
          onClose={handleClosePreview}
          src={fullPreviewUrl}
          name={finalFile?.name}
          showDownload={showDownloadButton}
          onDownload={handleDownloadFromPreview}
        />
      )}
    </CardContainer>
  );
};

export type { FileCardProps };

export default FileCard;
