import { RedoOutlined } from '@ant-design/icons';
import { t, Trans } from '@lingui/macro';
import { useLingui } from '@lingui/react';
import { Button, Card, Col, notification, Row, Space, Tooltip } from 'antd';
import { useRef } from 'react';
import { ImageAnnotator } from '../../components/annotator';
import {
  AnnotatorProvider,
  useStoreInstance,
} from '../../components/annotator/store-context';
import { DEFAULT_REFRESH_INTERVAL } from '../../consts';
import { StyledUpload, useAntdLocalFiles } from '../../hooks/useAntLocalFiles';
import { useAutoRefreshFlag } from '../../hooks/useAutoRefreshFlag';
import {
  BaseResult,
  DriverLicenseResult,
  IDCardResult,
  InvoiceResult,
  InvoiceResultDocClsBase,
  InvoiceResultDocCls,
  JobResponse,
  JobStatus,
  ModelStatus,
  OtherDocumentsResult,
  ProcessTypes,
} from '../../models';
import { useCreateKieJob, useKieJob } from '../../queries';
import {
  extractShapesFromDriverLicenseResults,
  extractShapesFromIDCardResults,
  extractShapesFromInvoiceResults,
  extractShapesFromOtherDocumentsResults,
} from '../../utils/shape-convert';
import { ExtractInformation } from './extracted-info';

export interface KIEProps {
  title: string;
  processType: ProcessTypes;
  valueCopyable?: boolean;
}

const KIEPage = ({ title, processType, valueCopyable = false }: KIEProps) => {
  const { i18n } = useLingui();
  const etractedInforElemenRef = useRef<HTMLDivElement>();
  const storeInstance = useStoreInstance();
  const {
    isRefreshing,
    trigger: triggerRefresh,
    stop: stopRefresh,
  } = useAutoRefreshFlag({
    onStopByTimeout() {
      notification.info({
        message: t(
          i18n,
        )`Request may need more time to process, please click Refresh button to retrieve results.`,
      });
    },
  });
  const { antdUploadProps, selectedFileUri, selectedFile } = useAntdLocalFiles({
    maxCount: 1,
  });
  const createKieJobMutation = useCreateKieJob();
  const kieJobQuery = useKieJob(createKieJobMutation.data, {
    enabled: createKieJobMutation.isSuccess,
    retry: false,
    refetchInterval: isRefreshing ? DEFAULT_REFRESH_INTERVAL : false,
    onSuccess(data: JobResponse<BaseResult>) {
      if (data.status === JobStatus.Success) {
        // Set data for annotator
        let newShapes;
        switch (processType) {
          case ProcessTypes.Invoice:
            newShapes = extractShapesFromInvoiceResults(
              data.data as InvoiceResultDocCls,
            );
            break;
          case ProcessTypes.IDCard:
            newShapes = extractShapesFromIDCardResults(
              data.data as IDCardResult,
            );
            break;
          case ProcessTypes.DriverLicense:
            newShapes = extractShapesFromDriverLicenseResults(
              data.data as DriverLicenseResult,
            );
            break;
          case ProcessTypes.BasicOCR:
            newShapes = extractShapesFromOtherDocumentsResults(
              data.data as OtherDocumentsResult,
            );
            break;
          default:
            throw new Error(`Unhandled Process type ${processType}`);
        }

        const cropImage = data.files.find(
          (item) => item.file_category === 'Crop',
        )?.file_url;

        storeInstance.setShapes(newShapes);

        if (cropImage) {
          storeInstance.setBackground(cropImage);
        }

        // stop refetch interval if completed sooner than expected
        stopRefresh();

        switch (data.data.status) {
          case ModelStatus.BlurryWithData:
          case ModelStatus.BlurryWithoutData:
            notification.warning({
              message: t(i18n)`Key Information Extraction`,
              description: t(
                i18n,
              )`The results might not be correct because blurriness is detected on the uploaded image.`,
            });
            break;
          case ModelStatus.Success:
            etractedInforElemenRef.current?.scrollIntoView({
              behavior: 'smooth',
              block: 'start',
            });
            notification.success({
              message: t(i18n)`Key Information Extraction`,
              description: t(i18n)`Data extracted successfully!`,
            });
            break;
          default:
            notification.warning({
              message: t(i18n)`Key Information Extraction`,
              description: t(i18n)`No message from model status`,
            });
        }
      } else {
        if (data.status === JobStatus.ModelFailed) {
          switch (data.data.status) {
            case ModelStatus.NotMatch:
              notification.warning({
                message: t(i18n)`Key Information Extraction`,
                description: t(
                  i18n,
                )`Uploaded image is not match with template.`,
              });
              break;
            case ModelStatus.Failed:
              notification.warning({
                message: t(i18n)`Key Information Extraction`,
                description: t(
                  i18n,
                )`Can not extract information from uploaded image.`,
              });
              break;
            default:
              notification.warning({
                message: t(i18n)`Key Information Extraction`,
                description: t(i18n)`No message from model status`,
              });
          }
          stopRefresh();
        } else if (!isRefreshing) {
          notification.info({
            message: t(i18n)`Key Information Extraction`,
            description: t(
              i18n,
            )`Request may need more time to process, please click Refresh button to retrieve results.`,
          });
        }
      }
    },
  });

  return (
    <Row
      style={{
        height: '100%',
        width: '100%',
      }}
      gutter={[{ lg: 8 }, 8]}
      align="stretch"
    >
      <Col xs={24} md={24} lg={16} style={{ height: '100%' }}>
        <Card
          bordered
          title={title}
          extra={
            <Space>
              <Button
                type="primary"
                onClick={async () => {
                  try {
                    await createKieJobMutation.mutateAsync({
                      file: selectedFile.originFileObj,
                      processType,
                    });
                    triggerRefresh();
                    notification.success({
                      message: t(i18n)`Key Information Extraction`,
                      description: t(
                        i18n,
                      )`Extract information has been queued successfully.`,
                    });
                  } catch (error) {
                    notification.error({
                      message: t(i18n)`Key Information Extraction`,
                      description: t(i18n)`Extract information error: ${error}`,
                    });
                  }
                }}
                disabled={!selectedFile}
                loading={createKieJobMutation.isLoading || isRefreshing}
              >
                <Trans>Start Recognition</Trans>
              </Button>
              {createKieJobMutation.isSuccess && !isRefreshing && (
                <Tooltip title={<Trans>Refresh</Trans>}>
                  <Button
                    onClick={() => kieJobQuery.refetch()}
                    disabled={
                      kieJobQuery.data?.status === JobStatus.Success ||
                      kieJobQuery.data?.status === JobStatus.ModelFailed
                    }
                    icon={<RedoOutlined spin={kieJobQuery.isFetching} />}
                  />
                </Tooltip>
              )}
            </Space>
          }
          style={{
            height: '100%',
            display: 'flex',
            flexDirection: 'column',
          }}
          bodyStyle={{
            overflow: 'auto',
            display: 'flex',
            flexDirection: 'column',
            flex: 1,
            padding: 8,
          }}
        >
          <ImageAnnotator
            background={selectedFileUri}
            initialShapes={[]}
            readOnly
          />
          <div style={{ height: 8 }} />
          <StyledUpload
            accept=".jpg,.png,.jpeg"
            listType="picture-card"
            {...antdUploadProps}
            onChange={({ fileList, ...rest }) => {
              antdUploadProps.onChange({ fileList, ...rest });
              storeInstance.setShapes([]);
              createKieJobMutation.reset();
            }}
          >
            {antdUploadProps.fileList.length <= 8 && <Trans>+ Upload</Trans>}
          </StyledUpload>
        </Card>
      </Col>
      <Col
        xs={24}
        md={24}
        lg={8}
        style={{ height: '100%' }}
        ref={etractedInforElemenRef}
      >
        <ExtractInformation
          copyable={valueCopyable}
          response={kieJobQuery.data as JobResponse<BaseResult>}
        />
      </Col>
    </Row>
  );
};

export default function (props: KIEProps) {
  return (
    <AnnotatorProvider>
      <KIEPage {...props} />
    </AnnotatorProvider>
  );
}

