import PropTypes from 'prop-types';
import classnames from 'classnames';
import { geoPath } from 'd3-geo';
import { getStateName } from "../../../utils/election/index.js";
import getColor from "../../../utils/colors/getColor.js";
import IfActive from "../../application/IfActive/index.js";
import useBoundaryProps from '../hooks/useBoundaryProps';
import useTopojson from '../hooks/useTopojson';
import TooltipTrigger from '../OptionalTooltip';
import SpecialElections from '../SpecialElections';
import StateLabel from '../StateLabel';
const defaultBoundaryProps = {
  fill: 'white',
  stroke: getColor('warmgray-30')
};
const defaultLabelProps = {
  fill: getColor('warmgray-100')
};

/**
 * SVG content component to render all states in the country. It can optionally
 * render state labels using AP abbreviations.
 */
const States = function States(props) {
  const {
    topo,
    mapName,
    specials,
    labelStyle,
    tooltip,
    customClasses,
    getBoundaryProps,
    getLabelProps,
    badge: Badge
  } = props;
  const {
    stateShapeClass,
    stateShapeClassesByCode = {},
    stateLabelClass,
    stateLabelClassesByCode = {},
    stateLabelLeaderLineClass,
    stateLabelLeaderLineClassesByCode = {},
    specialClasses
  } = customClasses;
  const {
    states: {
      features
    }
  } = useTopojson(topo, {
    objects: ['states']
  });
  const boundaryProps = useBoundaryProps({
    getProps: getBoundaryProps,
    defaults: defaultBoundaryProps
  });
  const labelProps = useBoundaryProps({
    getProps: getLabelProps,
    defaults: defaultLabelProps
  });
  const path = geoPath();
  return <g>
      {features.map(({
      properties
    }) => <TooltipTrigger key={properties.code} as="g" tooltip={tooltip} props={properties}>
          <path className={classnames(stateShapeClass, stateShapeClassesByCode[properties.code])} d={properties.d} {...boundaryProps(properties)} />
        </TooltipTrigger>)}
      <SpecialElections states={specials} tooltip={tooltip} customClasses={specialClasses} position={mapName} />
      <IfActive active={!!Badge}>
        {features.map(feat => {
        const {
          properties: ps
        } = feat;
        const bbox = path.bounds(feat);
        return <TooltipTrigger key={ps.code} as="g" tooltip={tooltip} props={ps}>
              <Badge {...ps} cx={bbox[1][0]} cy={bbox[0][1]} />
            </TooltipTrigger>;
      })}
      </IfActive>
      <IfActive active={!!labelStyle}>
        {features.map(({
        properties: ps
      }) => <TooltipTrigger key={ps.code} as="g" tooltip={tooltip} props={ps}>
            <StateLabel center={ps.center} labelOffset={ps.labelOffset} labelLimits={ps.labelLimits} label={getStateName(ps.code, {
          format: labelStyle
        })} className={classnames(stateLabelClass, stateLabelClassesByCode[ps.code])} leaderLineClassName={classnames(stateLabelLeaderLineClass, stateLabelLeaderLineClassesByCode[ps.code])} {...labelProps(ps)} />
          </TooltipTrigger>)}
      </IfActive>
    </g>;
};
States.defaultProps = {
  specials: undefined,
  labelStyle: undefined,
  customClasses: {},
  tooltip: undefined,
  getBoundaryProps: undefined,
  getLabelProps: undefined,
  badge: undefined
};
States.propTypes = {
  /**
   * The URL to pull a TopoJSON from
   */
  topo: PropTypes.string.isRequired,
  /**
   * Which kind of state map we're rendering, used for positioning special
   * elections
   */
  mapName: PropTypes.oneOf(['geo', 'carto']).isRequired,
  /**
   * An array of pairs of state codes and color names for special elections
   */
  specials: PropTypes.arrayOf(PropTypes.shape({
    color: PropTypes.string,
    code: PropTypes.string
  })),
  /**
   * The label style to use, either AP abbreviations or postal codes
   */
  labelStyle: PropTypes.oneOf(['ap_abbr', 'abbr']),
  /**
   * A tooltip object
   */
  tooltip: PropTypes.shape({}),
  /**
   * Custom CSS classes to style the map
   */
  customClasses: PropTypes.shape({
    stateShapeClass: PropTypes.string,
    stateShapeClassesByCode: PropTypes.shape({}),
    stateLabelClass: PropTypes.string,
    stateLabelClassesByCode: PropTypes.shape({}),
    stateLabelLeaderLineClass: PropTypes.string,
    stateLabelLeaderLineClassesByCode: PropTypes.shape({}),
    specialClasses: PropTypes.shape({})
  }),
  /**
   * An accessor function to generate props for a specific boundary
   */
  getBoundaryProps: PropTypes.func,
  /**
   * An accessor function to generate props for a specific boundary's label
   */
  getLabelProps: PropTypes.func,
  /**
   * How to render badges
   */
  badge: PropTypes.elementType
};
export default States;