import {
  BigFiveDomain,
  IpipNeoItem,
  ipipNeo120Items,
  ipipNeo300Items,
} from '@/questionairies/bigfive/neo-data';

const reverseItems = new Set([
  2, 4, 6, 8, 10, 12, 16, 18, 19, 20, 22, 24, 26, 28, 29, 30, 32, 34,
  36, 38, 39, 44, 46, 48, 49,
]);

const dimensions = {
  extraversion: [1, 6, 11, 16, 21, 26, 31, 36, 41, 46],
  agreeableness: [2, 7, 12, 17, 22, 27, 32, 37, 42, 47],
  conscientiousness: [3, 8, 13, 18, 23, 28, 33, 38, 43, 48],
  emotionalStability: [4, 9, 14, 19, 24, 29, 34, 39, 44, 49],
  openness: [5, 10, 15, 20, 25, 30, 35, 40, 45, 50],
};

export function calculateBigFiveResults(answers: string[]) {
  const scoreItem = (questionId: number) => {
    const raw = Number(answers[questionId - 1] || 0);
    if (!raw) return 0;
    return reverseItems.has(questionId) ? 6 - raw : raw;
  };

  return Object.fromEntries(
    Object.entries(dimensions).map(([key, items]) => {
      const score = items.reduce((sum, item) => sum + scoreItem(item), 0);
      return [
        key,
        {
          score,
          average: score / items.length,
        },
      ];
    }),
  );
}

export const ipipNeoItemsByVersion = {
  120: ipipNeo120Items,
  300: ipipNeo300Items,
} as const;

export function calculateIpipNeoResults(
  answers: string[],
  items: IpipNeoItem[],
) {
  const domainTotals = new Map<BigFiveDomain, { score: number; count: number }>();
  const facetTotals = new Map<string, { score: number; count: number }>();

  items.forEach((item, index) => {
    const raw = Number(answers[index] || 0);
    const score = raw ? (item.reverse ? 6 - raw : raw) : 0;

    const domain = domainTotals.get(item.domain) || { score: 0, count: 0 };
    domain.score += score;
    domain.count += 1;
    domainTotals.set(item.domain, domain);

    const facet = facetTotals.get(item.facet) || { score: 0, count: 0 };
    facet.score += score;
    facet.count += 1;
    facetTotals.set(item.facet, facet);
  });

  const toResults = (totals: Map<string, { score: number; count: number }>) =>
    Object.fromEntries(
      [...totals.entries()].map(([key, value]) => [
        key,
        {
          score: value.score,
          average: value.count ? value.score / value.count : 0,
          itemCount: value.count,
        },
      ]),
    );

  return {
    domains: toResults(domainTotals),
    facets: toResults(facetTotals),
  };
}
