import { selectorFamily } from 'recoil';
import lodashGet from 'lodash/get';
import { getContestStatus, getCandidatesSortedByResults, getContestCandidateColors, resolveContestId } from "../../../utils/election/index.js";
import combinedMetadata from '../atoms/combinedMetadata';
import contestSummaryResults from '../atoms/contestSummaryResults';
import contestCountyResults from '../atoms/contestCountyResults';
import cycleCandidateMetadata from '../atoms/cycleCandidateMetadata';
import { formattedContestCallEventsFromCalls } from '../utils';
const getData = ({
  get,
  key
}) => {
  if (!key) return undefined;
  if (key.startsWith('contest')) return get(contestSummaryResults(key));
  const [, contestId] = key.split('::');
  const counties = get(contestCountyResults(contestId));
  if (!counties) return undefined;
  return {
    ...counties,
    data: counties.data.countiesByCode[key]
  };
};

/**
 * {
 *   combinedMetadata: {},
 *   summary: {},
 *   contestStatus: {},
 *   candidateResults: {},
 *   candidateCallStatus: {},
 *   sortedCandidateIds: [],
 * }
 */
const contest = selectorFamily({
  key: 'int-style.election.selectors.contest',
  get: key => ({
    get
  }) => {
    const contestId = resolveContestId(key);
    const metadata = get(combinedMetadata(contestId));
    const summary = getData({
      get,
      key
    });
    const contestMeta = lodashGet(metadata, 'data.contest', {});
    const candidatesMeta = lodashGet(metadata, 'data.candidates', {});
    const callEvents = formattedContestCallEventsFromCalls(key, lodashGet(summary, 'data.calls', []));
    const summaryResults = lodashGet(summary, 'data') && {
      ...lodashGet(summary, 'data', {}),
      ...callEvents
    };
    const candidatesMetadata = Object.values(candidatesMeta).filter(Boolean).map(c => {
      if (!c.cycleId) return c;
      const cycleMeta = get(cycleCandidateMetadata(c.cycleId));
      return {
        ...c,
        ...lodashGet(cycleMeta, 'data', {}),
        id: c.id
      };
    });
    const contestStatus = getContestStatus(contestMeta, candidatesMetadata, summaryResults);
    const candidateResults = Object.fromEntries(lodashGet(summaryResults, 'results', []).map(c => [c.id, c]));
    const sortedCandidateIds = getCandidatesSortedByResults({
      results: summaryResults,
      candidatesMetadata
    });
    const noCallStatuses = Object.fromEntries(candidatesMetadata.map(c => [c.id, 'no-call']));
    const candidateCallStatus = lodashGet(summaryResults, 'calls', []).reduce((cands, call) => {
      if (call.isRetracted) return cands;
      if (call.subjectType !== 'candidate') return cands;
      if (cands[call.subjectId] !== 'no-call') {
        // eslint-disable-next-line no-console
        console.warn(`Candidate ${call.subjectId} has multiple unretracted calls`);
      }
      return {
        ...cands,
        [call.subjectId]: call.type
      };
    }, noCallStatuses);
    const candidateColors = getContestCandidateColors({
      contest: contestMeta,
      candidates: candidatesMetadata
    });
    return {
      metadata: {
        lastUpdated: lodashGet(summary, 'metadata.lastUpdated')
      },
      data: {
        combinedMetadata: {
          contest: contestMeta,
          candidates: Object.fromEntries(candidatesMetadata.map(c => [c.id, c]))
        },
        candidates: candidatesMetadata,
        summary: summaryResults,
        callEvents,
        contestStatus,
        candidateResults,
        candidateCallStatus,
        sortedCandidateIds,
        candidateColors
      }
    };
  }
});
export default contest;