import { AutoTooltip, ModalFooter, ScrollerModal } from '@gpustack/core-ui';
import { exportJsonToExcel } from '@gpustack/core-ui/excel';
import { useIntl } from '@umijs/max';
import { Table, TableColumnType } from 'antd';
import React, { useEffect } from 'react';
import { useUsageFilters } from '../hooks/use-usage-filters';
import useQueryBreakdownList from '../services/use-query-breakdown-list';
import { withDeletedMark } from '../utils/deleted-label';
import getBreakdownRowKey from '../utils/get-breakdown-row-key';
import FilterBar from './filter-bar';

type DateType = 'date' | 'week' | 'month' | 'quarter' | 'year';
type ValueType = string | number | null;
const INITIAL_PAGE_PARAMS = {
  page: 1,
  perPage: 100
};

const ExportData: React.FC<{
  open: boolean;
  onCancel: () => void;
  initialScope: string;
  metaData: any;
  granularity: string;
  initialState: {
    activeRoutes: string[];
    activeApiKeys: ValueType[][];
    users: string[];
    start_date: string;
    end_date: string;
  };
  commonFilters: {
    scope: string;
    start_date: string;
    end_date: string;
    routes: string[];
    users: string[];
    api_keys: string[];
  };

  handlePickerChange: (picker: DateType) => void;
}> = (props) => {
  const {
    open,
    onCancel,
    initialScope,
    metaData,
    granularity,
    handlePickerChange,
    initialState
  } = props || {};
  const intl = useIntl();
  const deletedWord = intl.formatMessage({ id: 'usage.table.deleted' });

  // Members are forced to self scope, where the backend forbids grouping by
  // user (privacy) — including it 403s the export request. Drop the user
  // dimension (and its column) when we can't group by it.
  const canGroupByUser = initialScope !== 'self';
  const exportGroupBy = canGroupByUser
    ? ['date', 'user', 'route', 'api_key']
    : ['date', 'route', 'api_key'];

  const [pageParams, setPageParams] = React.useState<{
    page: number;
    perPage: number;
  }>(INITIAL_PAGE_PARAMS);

  const {
    fetchData: fetchExportData,
    loading,
    dataSource,
    cancelRequest
  } = useQueryBreakdownList({
    key: 'exportTableData'
  });

  const { filters, commonFilters, filterBar } = useUsageFilters({
    initialScope: initialScope,
    metaData,
    chartFilters: {
      metric: 'total_tokens',
      group_by: null,
      granularity: props.granularity || 'day'
    },
    initialState: initialState,
    summaryColumns: [],
    autoFetchOnFilterChange: true,
    onFetchData: ({
      chartFilters: nextChartFilters,
      filters: nextFilters,
      commonFilters: nextCommonFilters
    }) => {
      fetchExportData({
        ...pageParams,
        granularity: 'day',
        sort_by: '-date',
        group_by: exportGroupBy,
        filters: nextFilters,
        scope: initialScope,
        start_date: nextCommonFilters.start_date,
        end_date: nextCommonFilters.end_date
      });
    }
  });

  const exportTableColumns: TableColumnType<any>[] = [
    {
      title: intl.formatMessage({ id: 'resources.table.index' }),
      width: 80,
      render(text: any, row: any, index: number) {
        return index + 1;
      }
    },
    {
      title: intl.formatMessage({ id: 'dashboard.usage.export.date' }),
      dataIndex: ['date', 'label'],
      render: (text: string) => {
        return (
          <AutoTooltip ghost>
            <span className="text-primary">{text}</span>
          </AutoTooltip>
        );
      }
    },
    {
      title: intl.formatMessage({ id: 'usage.filter.group.model' }),
      dataIndex: ['route', 'label'],
      render: (text: string, record: any) => {
        return (
          <AutoTooltip ghost>
            {withDeletedMark(
              text,
              record?.route?.deleted,
              deletedWord,
              record?.route?.identity?.current?.route_id
            )}
          </AutoTooltip>
        );
      }
    },
    {
      title: intl.formatMessage({ id: 'dashboard.usage.export.user' }),
      dataIndex: ['user', 'label'],
      render: (text: string, record: any) => {
        return (
          <AutoTooltip ghost>
            {withDeletedMark(
              text,
              record?.user?.deleted,
              deletedWord,
              record?.user?.identity?.current?.user_id
            )}
          </AutoTooltip>
        );
      }
    },
    {
      title: intl.formatMessage({ id: 'usage.filter.group.apikey' }),
      dataIndex: ['api_key', 'label'],
      render: (text: string, record: any) => {
        return (
          <AutoTooltip ghost>
            {withDeletedMark(
              text,
              record?.api_key?.deleted,
              deletedWord,
              record?.api_key?.identity?.current?.api_key_id
            )}
          </AutoTooltip>
        );
      }
    },
    {
      title: (
        <AutoTooltip ghost>
          {intl.formatMessage({ id: 'usage.filter.inputTokens' })}
        </AutoTooltip>
      ),
      width: 130,
      dataIndex: 'input_tokens',
      render: (text: string, record: any) => {
        return <AutoTooltip ghost>{text}</AutoTooltip>;
      }
    },
    {
      title: (
        <AutoTooltip ghost>
          {intl.formatMessage({ id: 'usage.table.inputTokensCached' })}
        </AutoTooltip>
      ),
      width: 150,
      dataIndex: 'input_cached_tokens',
      render: (text: string, record: any) => {
        return <AutoTooltip ghost>{text}</AutoTooltip>;
      }
    },
    {
      title: (
        <AutoTooltip ghost>
          {intl.formatMessage({ id: 'usage.filter.outputTokens' })}
        </AutoTooltip>
      ),
      dataIndex: 'output_tokens',
      render: (text: string, record: any) => {
        return <AutoTooltip ghost>{text}</AutoTooltip>;
      }
    },
    {
      title: (
        <AutoTooltip ghost>
          {intl.formatMessage({ id: 'usage.filter.totalTokens' })}
        </AutoTooltip>
      ),
      dataIndex: 'total_tokens',
      render: (text: string, record: any) => {
        return <AutoTooltip ghost>{text}</AutoTooltip>;
      }
    },
    {
      title: (
        <AutoTooltip ghost>
          {intl.formatMessage({ id: 'usage.filter.apiRequests' })}
        </AutoTooltip>
      ),
      dataIndex: 'api_requests',
      render: (text: string, record: any) => {
        return <AutoTooltip ghost>{text}</AutoTooltip>;
      }
    }
  ];

  // Hide the User column when we can't group by user (self scope) — it'd be
  // empty otherwise.
  const visibleColumns = canGroupByUser
    ? exportTableColumns
    : exportTableColumns.filter(
        (c) => !(Array.isArray(c.dataIndex) && c.dataIndex[0] === 'user')
      );

  const handleSubmit = () => {
    exportJsonToExcel({
      fileName: `usage_export_${commonFilters.start_date}_${commonFilters.end_date}.xlsx`,
      sheets: [
        {
          jsonData: (dataSource.dataList || []).map((item: any) => ({
            date: item?.date?.label,
            user: withDeletedMark(
              item?.user?.label ?? '',
              item?.user?.deleted,
              deletedWord,
              item?.user?.identity?.current?.user_id
            ),
            route: withDeletedMark(
              item?.route?.label ?? '',
              item?.route?.deleted,
              deletedWord,
              item?.route?.identity?.current?.route_id
            ),
            api_key: withDeletedMark(
              item?.api_key?.label ?? '',
              item?.api_key?.deleted,
              deletedWord,
              item?.api_key?.identity?.current?.api_key_id
            ),
            input_tokens: item?.input_tokens,
            input_cached_tokens: item?.input_cached_tokens,
            output_tokens: item?.output_tokens,
            total_tokens: item?.total_tokens,
            api_requests: item?.api_requests
          })),
          sheetName: 'usage',
          fields: [
            'date',
            ...(canGroupByUser ? ['user'] : []),
            'route',
            'api_key',
            'input_tokens',
            'input_cached_tokens',
            'output_tokens',
            'total_tokens',
            'api_requests'
          ],
          fieldLabels: {
            date: intl.formatMessage({ id: 'dashboard.usage.export.date' }),
            user: intl.formatMessage({ id: 'dashboard.usage.export.user' }),
            route: intl.formatMessage({ id: 'usage.filter.group.model' }),
            api_key: intl.formatMessage({ id: 'usage.filter.group.apikey' }),
            input_tokens: intl.formatMessage({
              id: 'usage.filter.inputTokens'
            }),
            input_cached_tokens: intl.formatMessage({
              id: 'usage.table.inputTokensCached'
            }),
            output_tokens: intl.formatMessage({
              id: 'usage.filter.outputTokens'
            }),
            total_tokens: intl.formatMessage({
              id: 'usage.filter.totalTokens'
            }),
            api_requests: intl.formatMessage({ id: 'usage.filter.apiRequests' })
          },
          formatMap: {}
        }
      ]
    });
  };

  const handlePageChange = (page: number, pageSize: number) => {
    setPageParams({ page, perPage: pageSize });
    fetchExportData({
      ...pageParams,
      page,
      perPage: pageSize,
      granularity: 'day',
      group_by: exportGroupBy,
      filters,
      sort_by: '-date',
      scope: initialScope,
      start_date: commonFilters.start_date,
      end_date: commonFilters.end_date
    });
  };

  const handleOnCancel = () => {
    onCancel?.();
  };

  useEffect(() => {
    if (open) {
      setPageParams(INITIAL_PAGE_PARAMS);
      fetchExportData({
        ...INITIAL_PAGE_PARAMS,
        granularity: 'day',
        group_by: exportGroupBy,
        filters,
        sort_by: '-date',
        scope: initialScope,
        start_date: commonFilters.start_date,
        end_date: commonFilters.end_date
      });
    } else {
      cancelRequest();
    }
  }, [open]);

  return (
    <ScrollerModal
      title={intl.formatMessage({ id: 'dashboard.usage.export' })}
      open={open}
      centered={false}
      onCancel={handleOnCancel}
      destroyOnHidden={true}
      closeIcon={true}
      mask={{
        closable: false
      }}
      keyboard={false}
      width={1280}
      style={{
        top: '10%'
      }}
      footer={
        <ModalFooter
          onOk={handleSubmit}
          onCancel={handleOnCancel}
          okText={intl.formatMessage({ id: 'common.button.export' })}
        ></ModalFooter>
      }
    >
      <div
        style={{
          position: 'sticky',
          top: 0,
          zIndex: 1,
          backgroundColor: 'var(--ant-color-bg-elevated)',
          paddingBottom: 8
        }}
      >
        <FilterBar
          {...filterBar}
          pageType="modal"
          handlePickerChange={handlePickerChange}
        ></FilterBar>
      </div>
      <Table
        columns={visibleColumns}
        className={'scroll-table'}
        tableLayout={'auto'}
        style={{ width: '100%', marginTop: '16px', minHeight: 400 }}
        dataSource={dataSource.dataList || []}
        rowKey={(record) => getBreakdownRowKey(record, 'export')}
        loading={{
          spinning: loading,
          size: 'middle'
        }}
        virtual
        scroll={{ y: 400 }}
        pagination={{
          size: 'small',
          pageSize: pageParams.perPage,
          current: pageParams.page,
          total: dataSource.total || 0,
          onChange: handlePageChange,
          hideOnSinglePage: pageParams.perPage === 100,
          showSizeChanger: true
        }}
      ></Table>
    </ScrollerModal>
  );
};

export default ExportData;
