import PropTypes from 'prop-types';
import { useZoom, Canvas } from "../../maps/index.js";
import { useMapColors, useSortMapBoundariesCompare } from "../../../hooks/election/index.js";
import { ElectionMapLegend, ModuleTitle } from "../index.js";
import useTooltip from "../../../hooks/useTooltip/index.js";
import { useState, useMemo } from 'react';
import { useContainerBreakpointIsAtMost } from "../../../hooks/breakpoint/index.js";
import { IfActive } from "../../application/index.js";
import cx from "../../../utils/css/cx.js";
import DistrictTooltip from './Tooltip';
import classes from './styles.module.scss';
import MapToggle from './MapToggle';
import toggleSettings from './toggleSettings';
import mapGeoTypes from './mapGeographyTypes';
import useMapExtent from './useMapExtent';
import { MapColorContext } from './context';
import Badge from './Badge';
import SplitEvs from './SplitEvs';
import MobilePanning from './MobilePanning';
import SpecialElections from './SpecialElections';
const cls = cx.merge(classes);

/**
 * A toggleable nationwide map of House, Senate or gubernatorial results.
 */
const NationalToggleMap = function NationalToggleMap(props) {
  const {
    collectionId,
    contestLevel,
    reporterNote: reporterNoteProps,
    headline,
    eyebrow,
    defaultToggleState,
    disableToggle,
    layout,
    disableModuleTitle,
    disableZoom
  } = props;
  const toggleVals = toggleSettings[contestLevel];
  const {
    type: mapGeography,
    component: Map
  } = mapGeoTypes[contestLevel];
  const [mapFormat, setMapFormat] = useState(() => {
    const toggle = toggleVals.find(t => t.key === defaultToggleState);
    return toggle || toggleVals[0];
  });
  const colors = useMapColors({
    collectionId,
    mapGeography
  });
  const {
    fipsToPalette
  } = colors;
  const specialElections = useMemo(() => [...fipsToPalette].filter(([code]) => code && code.includes('special')).map(d => d[1]), [fipsToPalette]);
  const sortBoundariesCompare = useSortMapBoundariesCompare(colors);
  const atMostMd = useContainerBreakpointIsAtMost('md');
  const zoomable = !disableZoom && false;
  const [ref, mapExtent] = useMapExtent({
    zoomable,
    layout
  });
  const zoom = useZoom({
    zoomable,
    viewExtent: mapExtent
  });
  const customClasses = useMemo(() => {
    if (!atMostMd) return undefined;
    if (layout !== 'embed') return undefined;
    return {
      stateLabelClass: cls('embedStateLabels', 'override')
    };
  }, [layout, atMostMd]);
  const tooltip = useTooltip({
    content: DistrictTooltip,
    props: {
      colors,
      getShowActiveGeo: code => !!colors.fipsToPalette.get(code)
    },
    displayProps: {
      unstyled: true
    }
  });
  const mapClasses = {
    mapContainer: classes.mapContainer
  };
  const showBadges = mapFormat.key === 'carto' || mapFormat.key === 'dots' && zoomable;
  const showSplitEvs = contestLevel === 'president' && mapFormat.key === 'geo';
  return <div className={classes.container}>
      <IfActive active={!disableModuleTitle}>
        <ModuleTitle headline={headline} eyebrow={{
        isLive: true,
        ...eyebrow
      }} reporterNote={reporterNoteProps} />
      </IfActive>

      <IfActive active={layout === 'module'}>
        <div className={classes.controls}>
          <MapToggle mapFormats={toggleVals} mapFormat={mapFormat} setMapFormat={setMapFormat} />
          <ElectionMapLegend palettes={colors.palettes} includeNoClearLeader={colors.includeNoClearLeader} includeRunoff={colors.includeRunoff} includeFlip={colors.includeFlip && showBadges} />
        </div>
      </IfActive>

      <IfActive active={layout === 'embed' && !disableToggle}>
        <div className={classes.embedControls}>
          <MapToggle mapFormats={toggleVals} mapFormat={mapFormat} setMapFormat={setMapFormat} />
        </div>
      </IfActive>

      <MobilePanning layout={layout} contestLevel={contestLevel}>
        <MapColorContext.Provider value={colors}>
          <div ref={ref} className={classes.mapContainer}>
            <Canvas zoomable zoom={zoom} viewBoxMargin={1} customClasses={mapClasses}>
              <Map format={mapFormat.key} colors={colors} sortBoundariesCompare={sortBoundariesCompare} tooltip={tooltip} badge={showBadges ? Badge : undefined} customClasses={customClasses} />
            </Canvas>

            <div className={cls('extras', {
            isZoomed: zoom.transform.zoomLevel > 0,
            zoomable
          })}>
              <IfActive active={showSplitEvs}>
                <SplitEvs fipsToPalette={fipsToPalette} colors={colors} tooltip={tooltip} isZoomed={zoom.transform.zoomLevel > 0} zoomable={zoomable} layout={layout} />
              </IfActive>

              <IfActive active={specialElections.length > 0}>
                <SpecialElections elections={specialElections} colors={colors} contestLevel={contestLevel} tooltip={tooltip} isZoomed={zoom.transform.zoomLevel > 0} zoomable={zoomable} layout={layout} />
              </IfActive>
            </div>
          </div>
        </MapColorContext.Provider>
      </MobilePanning>

      <IfActive active={layout !== 'module'}>
        <div className={classes.controls}>
          <ElectionMapLegend palettes={colors.palettes} includeNoClearLeader={colors.includeNoClearLeader} includeRunoff={colors.includeRunoff} includeFlip={colors.includeFlip && showBadges} />
        </div>
      </IfActive>
    </div>;
};
NationalToggleMap.defaultProps = {
  contestLevel: 'house',
  reporterNote: undefined,
  eyebrow: undefined,
  headline: undefined,
  defaultToggleState: undefined,
  disableToggle: false,
  disableModuleTitle: false,
  disableZoom: false,
  layout: 'module'
};
NationalToggleMap.propTypes = {
  /**
   * The ID of the contest collection to use
   */
  collectionId: PropTypes.string.isRequired,
  /**
   * The contest level the map is displaying.
   */
  contestLevel: PropTypes.oneOf(['house', 'senate', 'president', 'governors']),
  /**
   * An optional reporter note to include as an inline annotation for this
   * module. Should be passed through to the `ReporterNote` component.
   */
  reporterNote: PropTypes.shape({}),
  /**
   * Custom configuration for the module eyebrow
   */
  eyebrow: PropTypes.shape({}),
  /**
   * Custom headline
   */
  headline: PropTypes.string,
  /**
   * A map type key that specifies which kind of map to start with.
   */
  defaultToggleState: PropTypes.string,
  /**
   * Disable toggling between map types (only applies in `embed` layout)
   */
  disableToggle: PropTypes.bool,
  /**
   * Render without the eyebrow, timestamp, etc.
   */
  disableModuleTitle: PropTypes.bool,
  /**
   * A layout of the component to differentiate between module and embed.
   */
  layout: PropTypes.oneOf(['module', 'embed']),
  /**
   * Disable zoomability
   */
  disableZoom: PropTypes.bool
};
export default NationalToggleMap;