import { useEffect, useMemo, useState } from 'react';
import {
  Box,
  CircularProgress,
  FormControl,
  MenuItem,
  Select,
  Typography
} from '@mui/material';
import type { SelectChangeEvent } from '@mui/material';
import { makeStyles } from 'tss-react/mui';

import { useAppDispatch, useAppSelector } from '../store';
import { selectVitalSeries, selectVitals } from '../store/hostsSlice/selectors';
import { fetchHostObservables, fetchVitalMagnified } from '../store/hostsSlice/thunks';
import { formatTimestamp } from '../utils/format';
import { MeasurementChart } from './MeasurementChart';
import { MeasurementsDialog } from './MeasurementsDialog';

const useStyles = makeStyles()(theme => ({
  // 2-column layout: meta block on the left, chart on the right.
  body: {
    display: 'flex',
    alignItems: 'flex-start',
    justifyContent: 'flex-start',
    gap: 24,
    flexWrap: 'wrap',
    marginTop: 16
  },
  metaColumn: {
    flex: '0 0 360px',
    minWidth: 400
  },
  metaGrid: {
    display: 'grid',
    gridTemplateColumns: 'minmax(140px, max-content) 1fr',
    rowGap: 6,
    columnGap: 24
  },
  metaLabel: {
    color: theme.palette.text.muted
  },
  selector: {
    minWidth: 160
  },
  chartColumn: {
    flex: '0 0 auto',
    width: '100%',
    maxWidth: 400
  },
  chartFrame: {
    cursor: 'pointer',
    border: `1px solid ${theme.palette.divider}`,
    '&:hover': {
      borderColor: theme.palette.link.primary
    }
  },
  empty: {
    padding: '12px 0',
    color: theme.palette.text.muted,
    fontStyle: 'italic'
  }
}));

interface Props {
  hostkey: string;
  hostname: string;
}

const decodeUnits = (units?: string): string => {
  if (!units) return '';
  try {
    return decodeURIComponent(units);
  } catch {
    return units;
  }
};

const formatVitalTimestamp = (ts?: number | null): string =>
  formatTimestamp(ts, { withSeconds: true });

export const MeasurementsSection = ({ hostkey, hostname }: Props) => {
  const { classes } = useStyles();
  const dispatch = useAppDispatch();
  const vitals = useAppSelector(state => selectVitals(state, hostkey));
  const [selectedObservable, setSelectedObservable] = useState<string>('loadavg');
  const [dialogOpen, setDialogOpen] = useState(false);

  const available = vitals.meta?.obs ?? [];
  const currentObservable = available.find(o => o.id === selectedObservable);
  const series4h = useAppSelector(state =>
    selectVitalSeries(state, hostkey, currentObservable?.id ?? selectedObservable, 'past4h')
  );

  // Load the full list of available observables once per host.
  useEffect(() => {
    if (hostkey) dispatch(fetchHostObservables(hostkey));
  }, [dispatch, hostkey]);

  // When the observable list arrives, seed `selectedObservable` if our current pick
  // isn't present.
  useEffect(() => {
    if (available.length > 0 && !available.some(o => o.id === selectedObservable)) {
      setSelectedObservable(available[0].id);
    }
  }, [available, selectedObservable]);

  // Load 4h preview series whenever the selected observable changes.
  useEffect(() => {
    if (!currentObservable?.timestamp) return;
    dispatch(
      fetchVitalMagnified({
        hostkey,
        obs: currentObservable.id,
        lastUpdated: currentObservable.timestamp,
        timeFrame: 6
      })
    );
  }, [dispatch, hostkey, currentObservable?.id, currentObservable?.timestamp]);

  const units = decodeUnits(currentObservable?.units);
  const series = series4h?.data ?? [];
  const loading = series4h?.loading ?? false;
  const lastValue = useMemo(() => {
    if (series.length === 0) return null;
    const last = series[series.length - 1];
    return typeof last[1] === 'number' ? last[1] : null;
  }, [series]);

  const handleSelect = (e: SelectChangeEvent<string>) => setSelectedObservable(e.target.value);

  if (vitals.metaStatus === 'idle' || vitals.metaStatus === 'loading') {
    return (
      <Box sx={{ display: 'flex', alignItems: 'center', height: 80 }}>
        <CircularProgress size={20} />
      </Box>
    );
  }

  if (available.length === 0) {
    return (
      <div className={classes.empty}>
        No monitoring data has been collected for this host yet.
      </div>
    );
  }

  return (
    <Box>
      <div className={classes.body}>
        <div className={classes.metaColumn}>
          <FormControl size="small" className={classes.selector} sx={{ mb: 2 }}>
            <Select
              value={selectedObservable}
              onChange={handleSelect}
              variant="outlined"
              renderValue={value => String(value)}
            >
              {available.map(o => (
                <MenuItem key={o.id} value={o.id}>
                  {o.id}
                  {o.description ? ` (${o.description})` : ''}
                </MenuItem>
              ))}
            </Select>
          </FormControl>

          <div className={classes.metaGrid}>
            <Typography className={classes.metaLabel}>Last updated:</Typography>
            <Typography>{formatVitalTimestamp(currentObservable?.timestamp ?? vitals.meta?.lastUpdated)}</Typography>

            <Typography className={classes.metaLabel}>Unit:</Typography>
            <Typography>{units || '—'}</Typography>

            <Typography className={classes.metaLabel}>Last measured value:</Typography>
            <Typography>{lastValue != null ? lastValue.toFixed(2) : 'not available'}</Typography>
          </div>
        </div>

        <div className={classes.chartColumn}>
          {loading ? (
            <Box sx={{ display: 'flex', alignItems: 'center', height: 200 }}>
              <CircularProgress size={20} />
            </Box>
          ) : series.length > 0 ? (
            <div
              className={classes.chartFrame}
              role="button"
              onClick={() => setDialogOpen(true)}
              title="Click to expand"
            >
              <MeasurementChart series={series} height={220} compact />
            </div>
          ) : (
            <div className={classes.empty}>No data points for this measurement.</div>
          )}
        </div>
      </div>

      {currentObservable && (
        <MeasurementsDialog
          open={dialogOpen}
          onClose={() => setDialogOpen(false)}
          hostkey={hostkey}
          hostname={hostname}
          obs={currentObservable}
          lastUpdated={vitals.meta?.lastUpdated ?? currentObservable.timestamp ?? 0}
        />
      )}
    </Box>
  );
};
