import {Fragment, useEffect} from 'react';
import styled from '@emotion/styled';
import {PlatformIcon} from 'platformicons';

import type {GridColumnHeader, GridColumnOrder} from 'sentry/components/gridEditable';
import GridEditable, {COL_WIDTH_UNDEFINED} from 'sentry/components/gridEditable';
import type {CursorHandler} from 'sentry/components/pagination';
import Pagination from 'sentry/components/pagination';
import {IconImage} from 'sentry/icons';
import {t} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import {browserHistory} from 'sentry/utils/browserHistory';
import {DismissId, usePageAlert} from 'sentry/utils/performance/contexts/pageAlert';
import {decodeScalar} from 'sentry/utils/queryString';
import {useLocation} from 'sentry/utils/useLocation';
import {RESOURCE_THROUGHPUT_UNIT} from 'sentry/views/performance/browser/resources';
import {
  FONT_FILE_EXTENSIONS,
  IMAGE_FILE_EXTENSIONS,
} from 'sentry/views/performance/browser/resources/shared/constants';
import {ResourceSpanOps} from 'sentry/views/performance/browser/resources/shared/types';
import type {ValidSort} from 'sentry/views/performance/browser/resources/utils/useResourceSort';
import {useResourcesQuery} from 'sentry/views/performance/browser/resources/utils/useResourcesQuery';
import {DurationCell} from 'sentry/views/starfish/components/tableCells/durationCell';
import {renderHeadCell} from 'sentry/views/starfish/components/tableCells/renderHeadCell';
import ResourceSizeCell from 'sentry/views/starfish/components/tableCells/resourceSizeCell';
import {SpanDescriptionCell} from 'sentry/views/starfish/components/tableCells/spanDescriptionCell';
import {ThroughputCell} from 'sentry/views/starfish/components/tableCells/throughputCell';
import {TimeSpentCell} from 'sentry/views/starfish/components/tableCells/timeSpentCell';
import {ModuleName, SpanFunction, SpanMetricsField} from 'sentry/views/starfish/types';
import {QueryParameterNames} from 'sentry/views/starfish/views/queryParameters';
import {DataTitles, getThroughputTitle} from 'sentry/views/starfish/views/spans/types';

const {
  SPAN_DESCRIPTION,
  SPAN_OP,
  SPAN_SELF_TIME,
  HTTP_RESPONSE_CONTENT_LENGTH,
  PROJECT_ID,
  SPAN_GROUP,
} = SpanMetricsField;

const {TIME_SPENT_PERCENTAGE} = SpanFunction;

const {SPM} = SpanFunction;

const RESOURCE_SIZE_ALERT = t(
  `If you're noticing unusually large resource sizes, try updating to SDK version 7.82.0 or higher.`
);

type Row = {
  'avg(http.response_content_length)': number;
  'avg(span.self_time)': number;
  'project.id': number;
  'span.description': string;
  'span.group': string;
  'span.op': `resource.${'script' | 'img' | 'css' | 'iframe' | string}`;
  'spm()': number;
  'sum(span.self_time)': number;
  'time_spent_percentage()': number;
};

type Column = GridColumnHeader<keyof Row>;

type Props = {
  sort: ValidSort;
  defaultResourceTypes?: string[];
};

function ResourceTable({sort, defaultResourceTypes}: Props) {
  const location = useLocation();
  const cursor = decodeScalar(location.query?.[QueryParameterNames.SPANS_CURSOR]);
  const {setPageInfo, pageAlert} = usePageAlert();

  const {data, isLoading, pageLinks} = useResourcesQuery({
    sort,
    defaultResourceTypes,
    cursor,
    referrer: 'api.performance.browser.resources.main-table',
  });

  const columnOrder: GridColumnOrder<keyof Row>[] = [
    {key: SPAN_DESCRIPTION, width: COL_WIDTH_UNDEFINED, name: t('Resource Description')},
    {
      key: `${SPM}()`,
      width: COL_WIDTH_UNDEFINED,
      name: getThroughputTitle('http'),
    },
    {key: `avg(${SPAN_SELF_TIME})`, width: COL_WIDTH_UNDEFINED, name: DataTitles.avg},
    {
      key: `${TIME_SPENT_PERCENTAGE}()`,
      width: COL_WIDTH_UNDEFINED,
      name: DataTitles.timeSpent,
    },
    {
      key: `avg(${HTTP_RESPONSE_CONTENT_LENGTH})`,
      width: COL_WIDTH_UNDEFINED,
      name: DataTitles['avg(http.response_content_length)'],
    },
  ];
  const tableData: Row[] = data;

  useEffect(() => {
    if (pageAlert?.message !== RESOURCE_SIZE_ALERT) {
      for (const row of tableData) {
        const encodedSize = row[`avg(${HTTP_RESPONSE_CONTENT_LENGTH})`];
        if (encodedSize >= 2147483647) {
          setPageInfo(RESOURCE_SIZE_ALERT, {dismissId: DismissId.RESOURCE_SIZE_ALERT});
          break;
        }
      }
    }
  }, [tableData, setPageInfo, pageAlert?.message]);

  const renderBodyCell = (col: Column, row: Row) => {
    const {key} = col;

    if (key === SPAN_DESCRIPTION) {
      const fileExtension = row[SPAN_DESCRIPTION].split('.').pop() || '';

      return (
        <DescriptionWrapper>
          <ResourceIcon fileExtension={fileExtension} spanOp={row[SPAN_OP]} />
          <SpanDescriptionCell
            moduleName={ModuleName.RESOURCE}
            projectId={row[PROJECT_ID]}
            spanOp={row[SPAN_OP]}
            description={row[SPAN_DESCRIPTION]}
            group={row[SPAN_GROUP]}
          />
        </DescriptionWrapper>
      );
    }
    if (key === 'spm()') {
      return <ThroughputCell rate={row[key]} unit={RESOURCE_THROUGHPUT_UNIT} />;
    }
    if (key === 'avg(http.response_content_length)') {
      return <ResourceSizeCell bytes={row[key]} />;
    }
    if (key === `avg(span.self_time)`) {
      return <DurationCell milliseconds={row[key]} />;
    }
    if (key === SPAN_OP) {
      const fileExtension = row[SPAN_DESCRIPTION].split('.').pop() || '';
      const spanOp = row[key];
      if (fileExtension === 'js' || spanOp === 'resource.script') {
        return <span>{t('JavaScript')}</span>;
      }
      if (fileExtension === 'css') {
        return <span>{t('Stylesheet')}</span>;
      }
      if (FONT_FILE_EXTENSIONS.includes(fileExtension)) {
        return <span>{t('Font')}</span>;
      }
      return <span>{spanOp}</span>;
    }
    if (key === 'time_spent_percentage()') {
      return (
        <TimeSpentCell
          percentage={row[key]}
          total={row[`sum(${SPAN_SELF_TIME})`]}
          op={row[SPAN_OP]}
        />
      );
    }
    return <span>{row[key]}</span>;
  };

  const handleCursor: CursorHandler = (newCursor, pathname, query) => {
    browserHistory.push({
      pathname,
      query: {...query, [QueryParameterNames.SPANS_CURSOR]: newCursor},
    });
  };

  return (
    <Fragment>
      <GridEditable
        data={tableData}
        isLoading={isLoading}
        columnOrder={columnOrder}
        columnSortBy={[
          {
            key: sort.field,
            order: sort.kind,
          },
        ]}
        grid={{
          renderHeadCell: column =>
            renderHeadCell({
              column,
              location,
              sort,
            }),
          renderBodyCell,
        }}
        location={location}
      />
      <Pagination pageLinks={pageLinks} onCursor={handleCursor} />
    </Fragment>
  );
}

function ResourceIcon(props: {fileExtension: string; spanOp: string}) {
  const {spanOp, fileExtension} = props;

  if (spanOp === ResourceSpanOps.SCRIPT) {
    return <PlatformIcon platform="javascript" />;
  }
  if (fileExtension === 'css') {
    return <PlatformIcon platform="css" />;
  }
  if (FONT_FILE_EXTENSIONS.includes(fileExtension)) {
    return <PlatformIcon platform="font" />;
  }
  if (spanOp === ResourceSpanOps.IMAGE || IMAGE_FILE_EXTENSIONS.includes(fileExtension)) {
    return <IconImage color="black" legacySize="20px" />;
  }
  return <PlatformIcon platform="unknown" />;
}

export default ResourceTable;

const DescriptionWrapper = styled('div')`
  display: flex;
  flex-wrap: wrap;
  gap: ${space(1)};
`;
