import * as React from 'react';
import {formatFileSize, formatNumeral} from '@/utils/numeral';
import {useFileMetadata, useFileUrl} from '@/categories/blob/react';
import {augmentTextFile, getMimeTypeDescription} from '@/utils/blob';
import clsx from 'clsx';
import {KeyValueTable} from '@/categories/information/react';
import {Refractor} from '@modal-soft/react-refractor';
import {useEnhanced} from '@modal-soft/react-utils';
import {CommonPreviewProps} from '@/categories/blob/react/common';

type TextFilePreviewDerivedComponent = HTMLDivElement;

export interface TextFilePreviewProps<F extends Partial<File> = Partial<File>>
  extends React.HTMLProps<TextFilePreviewDerivedComponent>, CommonPreviewProps<F> {}

export const TextFilePreview = React.forwardRef<TextFilePreviewDerivedComponent, TextFilePreviewProps>(({
  file,
  className,
  style,
  enhanced: enhancedProp = false,
  ...etcProps
}, forwardedRef) => {
  const { fileWithUrl } = useFileUrl({ file });
  const { fileWithMetadata, error } = useFileMetadata({
    file: fileWithUrl,
    augmentFunction: augmentTextFile,
  });
  const { enhanced } = useEnhanced({ enhanced: enhancedProp });

  if (!fileWithMetadata) {
    return null;
  }

  return (
    <div
      className={clsx(
        'flex flex-col sm:grid sm:grid-cols-3 gap-8 w-full',
        className,
      )}
      style={style}
    >
      <div className="h-full relative col-span-2">
        <div className="absolute top-0 left-0 w-full h-full">
          {
            typeof fileWithMetadata.metadata?.contents === 'string'
            && (
              <div
                {...etcProps}
                data-testid="preview"
                role="presentation"
                className="w-full h-full select-none overflow-hidden text-xs"
                ref={forwardedRef}
                key={`${fileWithMetadata.url}:${fileWithMetadata.type}`}
              >
                <Refractor
                  code={fileWithMetadata.metadata.contents}
                  language={fileWithMetadata.metadata.scheme}
                  lineNumbers={Boolean(fileWithMetadata.metadata.scheme)}
                />
              </div>
            )
          }
        </div>
      </div>
      <div className="flex-shrink-0 m-0 flex flex-col gap-4 justify-between">
        <KeyValueTable
          hiddenKeys
          data-testid="infoBox"
          properties={[
            Boolean(fileWithMetadata.name) && {
              key: 'Name',
              className: 'font-bold',
              valueProps: {
                children: fileWithMetadata.name,
                title: fileWithMetadata.name,
              },
            },
            (enhanced && Boolean(getMimeTypeDescription(fileWithMetadata.type, fileWithMetadata.name) || '(Loading)') || Boolean(fileWithMetadata.type)) && {
              key: 'Type',
              valueProps: {
                children: typeof fileWithMetadata.metadata?.schemeTitle === 'string' ? `${fileWithMetadata.metadata.schemeTitle} Source` : 'Text File',
              },
            },
            (enhanced && Boolean(formatFileSize(fileWithMetadata.size) || '(Loading)') || Boolean(fileWithMetadata.size)) && {
              key: 'Size',
              valueProps: {
                className: clsx(
                  !formatFileSize(fileWithMetadata.size) && 'opacity-50'
                ),
                title: `${formatNumeral(fileWithMetadata.size ?? 0)} byte(s)`,
                children: formatFileSize(fileWithMetadata.size) || '(Loading)',
              },
            },
            typeof fileWithMetadata.metadata?.lineCount === 'number'
            && typeof fileWithMetadata.metadata?.linesOfCode !== 'number'
            && {
              key: 'Lines',
              valueProps: {
                children: `${formatNumeral(fileWithMetadata.metadata.lineCount)} line(s)`
              },
            },
            typeof fileWithMetadata.metadata?.lineCount === 'number'
            && typeof fileWithMetadata.metadata?.linesOfCode === 'number'
            && {
              key: 'Lines',
              valueProps: {
                children: `${formatNumeral(fileWithMetadata.metadata.lineCount)} line(s), ${formatNumeral(fileWithMetadata.metadata.linesOfCode)} loc`,
              },
            },
            Array.isArray(fileWithMetadata.metadata?.languageMatches)
            && {
              key: 'Language',
              valueProps: {
                children: (
                  <dl
                    className="text-sm"
                  >
                    {fileWithMetadata.metadata!.languageMatches.slice(0, 3).map(([language, probability], index) => {
                      return (
                        <div key={index} className="flex justify-between">
                          <dt>
                            {language.slice(0, 1).toUpperCase()}
                            {language.slice(1)}
                          </dt>
                          <dd className="tabular-nums">
                            {(probability * 100).toFixed(3)}%
                            {' '}
                            <abbr title="probability">prob.</abbr>
                          </dd>
                        </div>
                      );
                    })}
                  </dl>
                ),
              },
            },
          ]}
        />
      </div>
    </div>
  );
});

TextFilePreview.displayName = 'TextFilePreview';
