import ShowChartIcon from '@mui/icons-material/ShowChart';
import Box from '@mui/material/Box';
import CircularProgress from '@mui/material/CircularProgress';
import IconButton from '@mui/material/IconButton';
import React from 'react';

import {
  PROGRAM_DATA_ELEMENT_TYPES,
  USER_PREFERENCES_KEYS,
  VISIBILITY_STATUSES,
} from '@tamanu/constants';
import { VITALS_DATA_ELEMENT_IDS } from '@tamanu/constants/surveys';
import { getNormalRangeByAge, useDateTime, VisuallyHidden } from '@tamanu/ui-components';
import { useUserPreferencesQuery } from '../api/queries/useUserPreferencesQuery';
import { useChartData } from '../contexts/ChartData';
import { useVitalChartData } from '../contexts/VitalChartData';
import {
  DateHeadCell,
  LimitedLinesCell,
  RangeTooltipCell,
  RangeValidatedCell,
} from './FormattedTableCell';
import { TranslatedText } from './Translation/TranslatedText';
import { ViewPhotoLink } from './ViewPhotoLink';

function VitalChartButton(props) {
  return (
    <IconButton color="primary" size="small" {...props}>
      <ShowChartIcon fontSize="small" />
      <VisuallyHidden>
        <TranslatedText stringId="vitals.showChart" fallback="Show chart" />
      </VisuallyHidden>
    </IconButton>
  );
}

const parseMultiselectValue = value => {
  if (!value) return;
  try {
    return JSON.parse(value).join(', ');
  } catch (e) {
    return value;
  }
};

const VitalsLimitedLinesCell = props => (
  <LimitedLinesCell maxWidth="75px" maxLines={2} data-testid="limitedlinescell-r6w3" {...props} />
);

const MeasureCell = React.memo(({ value, data }) => {
  const {
    setChartKeys,
    setModalTitle,
    setVitalChartModalOpen,
    visualisationConfigs,
    setIsInMultiChartsView,
  } = useVitalChartData();
  const visualisationConfig = visualisationConfigs.find(({ key }) => key === data.dataElementId);
  const { hasVitalChart = false } = visualisationConfig || {};
  // If the diastolic blood pressure(DBP) is selected, we want to show the systolic blood pressure(SBP) chart instead
  // This is a hacky solution because:
  // we need the visualisation configs to enable the two viz buttons that can click into the chart view, and at the same time they will pop up the same chart. Replacing DBP key with SBP is a hacky way to do it.
  //
  // The ideal way is to:
  // 1. just make one button for both SBP and DBP on web
  // 2. build a chart key on backend for the blood chart, build a customised viz config for it.
  //
  // Currently DBP and SBP data are both shown on the same chart (VitalBloodPressureChart), it should use SBP's visualisation_config and validation_criteria to render the chart

  const chartKey =
    visualisationConfig?.key === VITALS_DATA_ELEMENT_IDS.dbp
      ? VITALS_DATA_ELEMENT_IDS.sbp
      : visualisationConfig?.key;

  return (
    <Box
      flexDirection="row"
      display="flex"
      alignItems="center"
      justifyContent="space-between"
      data-testid="box-w3f4"
    >
      {value}
      {hasVitalChart && (
        <VitalChartButton
          onClick={() => {
            setChartKeys([chartKey]);
            setIsInMultiChartsView(false);
            setModalTitle(value);
            setVitalChartModalOpen(true);
          }}
          data-testid="iconbutton-t7kq"
        />
      )}
    </Box>
  );
});

const TitleCell = React.memo(({ value, selectedChartSurveyName }) => {
  const {
    allGraphedChartKeys,
    setChartKeys,
    setModalTitle,
    setVitalChartModalOpen,
    setIsInMultiChartsView,
  } = useVitalChartData();
  const { selectedChartTypeId } = useChartData();
  const { data: userPreferences, isSuccess, isLoading } = useUserPreferencesQuery();

  const graphPreferenceKey =
    selectedChartTypeId === null
      ? USER_PREFERENCES_KEYS.SELECTED_GRAPHED_VITALS_ON_FILTER
      : USER_PREFERENCES_KEYS.SELECTED_GRAPHED_CHARTS_ON_FILTER;

  let chartKeys = [];
  if (isSuccess) {
    const { [graphPreferenceKey]: rawGraphFilter = 'select-all' } = userPreferences;
    const graphFilter = rawGraphFilter.trim();

    chartKeys = ['select-all', ''].includes(graphFilter)
      ? allGraphedChartKeys
      : graphFilter.split(',').filter(key => allGraphedChartKeys.includes(key));
  }

  return (
    <Box
      flexDirection="row"
      display="flex"
      alignItems="center"
      justifyContent="space-between"
      data-testid="box-8p39"
    >
      {value}
      {isSuccess && allGraphedChartKeys.length > 1 && (
        <VitalChartButton
          onClick={() => {
            setChartKeys(chartKeys);
            setIsInMultiChartsView(true);
            setModalTitle(selectedChartSurveyName);
            setVitalChartModalOpen(true);
          }}
          data-testid="iconbutton-u6iz"
        />
      )}
      {isLoading && <CircularProgress size="1em" data-testid="circularprogress-wtcr" />}
    </Box>
  );
});

const getRecordedDateAccessor = (date, patient, onCellClick, isEditEnabled, chartTitle) => {
  return cells => {
    const { answerId, value, component } = cells[date];
    const isPhoto = component.dataElement.type === PROGRAM_DATA_ELEMENT_TYPES.PHOTO;

    if (isPhoto && value) {
      return (
        <ViewPhotoLink
          answerId={answerId}
          surveyId={component.surveyId}
          imageId={value}
          data-testid="viewphotolink-chrt"
          chartTitle={chartTitle}
        />
      );
    }

    const isCurrent = component.visibilityStatus === VISIBILITY_STATUSES.CURRENT;
    const isValid = isCurrent ? true : Boolean(value);
    const isCalculatedQuestion =
      component.dataElement.type === PROGRAM_DATA_ELEMENT_TYPES.CALCULATED;
    const onClick =
      isEditEnabled && !isCalculatedQuestion && !isPhoto && isValid
        ? () => void onCellClick(cells[date])
        : null;

    const isMultiSelect = component.dataElement.type === PROGRAM_DATA_ELEMENT_TYPES.MULTI_SELECT;
    const { config, historyLogs, validationCriteria } = cells[date];

    return (
      <RangeValidatedCell
        value={isMultiSelect ? parseMultiselectValue(value) : value}
        component={component}
        config={config}
        validationCriteria={{ normalRange: getNormalRangeByAge(validationCriteria, patient) }}
        isEdited={historyLogs.length > 1}
        onClick={onClick}
        ValueWrapper={VitalsLimitedLinesCell}
        data-testid={`rangevalidatedcell-${date}`}
      />
    );
  };
};

export const useChartsTableColumns = (
  selectedChartSurveyName,
  patient,
  recordedDates,
  onCellClick,
  isEditEnabled = false,
) => {
  const { formatShortest, formatTimeWithSeconds } = useDateTime();
  return [
    {
      key: 'measure',
      title: <TranslatedText stringId="general.table.column.measure" fallback="Measure" />,
      sortable: false,
      accessor: ({ value, config, validationCriteria }) => (
        <RangeTooltipCell
          value={value}
          config={config}
          validationCriteria={{ normalRange: getNormalRangeByAge(validationCriteria, patient) }}
          data-testid="rangetooltipcell-f4qi"
        />
      ),
      CellComponent: MeasureCell,
      TitleCellComponent: ({ value }) => (
        <TitleCell value={value} selectedChartSurveyName={selectedChartSurveyName} />
      ),
    },
    // create a column for each reading
    ...recordedDates
      .sort((a, b) => b.localeCompare(a))
      .map(date => ({
        title: <DateHeadCell value={date} data-testid={`dateheadcell-${date}`} />,
        sortable: false,
        key: date,
        accessor: getRecordedDateAccessor(
          date,
          patient,
          onCellClick,
          isEditEnabled,
          selectedChartSurveyName,
        ),
        exportOverrides: {
          title: `${formatShortest(date)} ${formatTimeWithSeconds(date)}`,
        },
      })),
  ];
};

export const useVitalsTableColumns = (patient, recordedDates, onCellClick, isEditEnabled) => {
  return useChartsTableColumns(
    <TranslatedText stringId="patient.vitals.title" fallback="Vitals" />,
    patient,
    recordedDates,
    onCellClick,
    isEditEnabled,
  );
};
