import { CopyOutlined, DownloadOutlined } from '@ant-design/icons';
import { t, Trans } from '@lingui/macro';
import { useLingui } from '@lingui/react';
import {
  Button,
  Card,
  Empty,
  notification,
  Row,
  Table,
  Typography,
} from 'antd';
import React from 'react';
import { CSVLink } from 'react-csv';
import { defaultStyles, JsonView } from 'react-json-view-lite';
import styled from 'styled-components';
import { useCopyToClipboard } from 'usehooks-ts';
import {
  useSelectedShapeId,
  useShapes,
} from '../../components/annotator/hooks';
import { useStoreInstance } from '../../components/annotator/store-context';
import { DefaultShapeData } from '../../components/annotator/types';
import { EditableCell } from '../../components/editable-cell';
import { useInitialCardHeight } from '../../hooks/useInitialCardHeight';
import { BaseResult, JobResponse } from '../../models';
import { shapesToCsv } from '../../utils/shape-convert';
import { isConfidentShape } from './utils';

import 'react-json-view-lite/dist/index.css';

type TabKey = 'extracted-information' | 'api-response';

const StyledCard = styled(Card)`
  height: 100%;
  display: flex;
  flex-direction: column;
  .ant-card-head > .ant-card-head-wrapper {
    display: none;
  }
`;

export function ExtractInformation({
  copyable = false,
  response,
}: {
  copyable: boolean;
  response?: JobResponse<BaseResult>;
}) {
  const [activeTabKey, setActiveTabKey] = React.useState<TabKey>(
    'extracted-information',
  );
  const shapes = useShapes();
  const tableAsCsv = shapesToCsv(shapes);
  const cardRef = React.useRef<HTMLDivElement>();

  const contentTabs: Record<TabKey, React.ReactNode> = {
    'extracted-information': (
      <ExtractedTable copyable={copyable} cardRef={cardRef} />
    ),
    'api-response': <ApiResponse response={response} />,
    // 'api-response': null,
  };

  return (
    <StyledCard
      ref={cardRef}
      tabList={[
        {
          key: 'extracted-information',
          tab: t`Extracted Information`,
        },
        {
          key: 'api-response',
          tab: t`API Response`,
        },
      ]}
      bordered
      activeTabKey={activeTabKey}
      onTabChange={(key: TabKey) => {
        setActiveTabKey(key);
      }}
      extra={
        <div>
          {!copyable && tableAsCsv.length > 1 && (
            <Button type="link">
              <CSVLink
                data={tableAsCsv}
                filename={`extracted_data_${new Date().toISOString()}.csv`}
              >
                <Trans>
                  Export CSV <DownloadOutlined />
                </Trans>
              </CSVLink>
            </Button>
          )}
        </div>
      }
      bodyStyle={{ overflowY: 'auto' }}
    >
      {contentTabs[activeTabKey]}
    </StyledCard>
  );
}

function ExtractedTable({
  copyable,
  cardRef,
}: {
  copyable?: boolean;
  cardRef: React.MutableRefObject<HTMLDivElement>;
}) {
  const { i18n } = useLingui();
  const storeInstance = useStoreInstance();
  const selectedShapeId = useSelectedShapeId();
  const shapes = useShapes<DefaultShapeData & { confidentScore: number }>();
  const tableAsCsv = shapesToCsv(shapes);
  const initialCardHeight = useInitialCardHeight(cardRef);
  return (
    <>
      {tableAsCsv.length > 1 && (
        <Row justify="end">
          <Button type="link">
            <CSVLink
              data={tableAsCsv}
              filename={`extracted_data_${new Date().toISOString()}.csv`}
            >
              <Trans>
                Export CSV <DownloadOutlined />
              </Trans>
            </CSVLink>
          </Button>
        </Row>
      )}
      <Table
        pagination={false}
        scroll={{
          y: initialCardHeight ? initialCardHeight - 50 : 680,
        }}
        onRow={(record) => {
          return {
            onClick() {
              storeInstance.setSelectedShape(record.key);
            },
          };
        }}
        rowSelection={{
          hideSelectAll: true,
          columnWidth: 0,
          selectedRowKeys: [selectedShapeId],
          renderCell() {
            return null;
          },
        }}
        columns={[
          {
            title: t(i18n)`Label`,
            width: 120,
            render(_, record) {
              return (
                <Typography.Text>{i18n._(record.data?.label)}</Typography.Text>
              );
            },
          },
          {
            title: t(i18n)`Value`,
            render(_, record) {
              return (
                <EditableCell
                  style={{
                    whiteSpace: 'pre-wrap',
                    backgroundColor: isConfidentShape(record)
                      ? 'unset'
                      : 'yellow',
                  }}
                  copyable={copyable}
                  editable={{
                    onChange(value) {
                      storeInstance.setShapes((prev) =>
                        prev.map((shape) => {
                          if (shape.id === record.id) {
                            if (!shape.data)
                              shape.data = {
                                label: '',
                                value: '',
                              };
                            shape.data.value = value;
                          }

                          return shape;
                        }),
                      );
                    },
                  }}
                >
                  {record.data?.value}
                </EditableCell>
              );
            },
          },
        ]}
        dataSource={shapes.map((shape) => ({
          key: shape.id,
          ...shape,
        }))}
      />
    </>
  );
}

interface ApiResponseProps {
  response?: JobResponse<BaseResult>;
}

function ApiResponse({ response }: ApiResponseProps) {
  const { i18n } = useLingui();
  const [_, copyToClipboard] = useCopyToClipboard();

  if (response) {
    return (
      <>
        <Row style={{ paddingBottom: 16 }} justify="end">
          <Button
            icon={<CopyOutlined />}
            type="link"
            onClick={() => {
              copyToClipboard(JSON.stringify(response, null, 2));
              notification.success({
                message: t(i18n)`Copied!`,
              });
            }}
          >{t(i18n)`Copy`}</Button>
        </Row>
        <JsonView
          data={response}
          style={defaultStyles}
          shouldInitiallyExpand={(level) => level < 3}
        />
      </>
    );
  }

  return (
    <Empty
      image={Empty.PRESENTED_IMAGE_SIMPLE}
      description={t(i18n)`No response.`}
    />
  );
}

