import type { AllIssues, ItemsInfo, RuleInfo } from './types.js';

type ScanItems = AllIssues['items'];
type ScanCategory = ScanItems[keyof ScanItems];
type ScanItemsLight = Pick<ScanItems, 'mustFix' | 'goodToFix' | 'needsReview' | 'passed'>;

/**
 * Builds pre-computed HTML groups to optimize Group by HTML Element functionality.
 * Keys are composite "html\x00xpath" strings to ensure unique matching per element instance.
 */
export const buildHtmlGroups = (rule: RuleInfo, items: ItemsInfo[], pageUrl: string) => {
  if (!rule.htmlGroups) {
    rule.htmlGroups = {};
  }

  items.forEach(item => {
    // Use composite key of html + xpath for precise matching
    const htmlKey = `${item.html || 'No HTML element'}\x00${item.xpath || ''}`;

    if (!rule.htmlGroups![htmlKey]) {
      // Create new group with the first occurrence
      rule.htmlGroups![htmlKey] = {
        html: item.html || '',
        xpath: item.xpath || '',
        message: item.message || '',
        screenshotPath: item.screenshotPath || '',
        displayNeedsReview: item.displayNeedsReview,
        pageUrls: [],
      };
    }

    if (!rule.htmlGroups![htmlKey].pageUrls.includes(pageUrl)) {
      rule.htmlGroups![htmlKey].pageUrls.push(pageUrl);
    }
  });
};

/*
// Commenting this out for now as we are not including htmlGroups in the embedded report payload to keep it lean.
// We can revisit this if we want to include htmlGroups in the future and need a reference builder for it.
const toHtmlGroupReference = (item: any) => {
  if (typeof item === 'string') {
    return item;
  }

  return `${item?.html || 'No HTML element'}\x00${item?.xpath || ''}`;
};

const cloneCategoryWithReferenceItems = (category: ScanCategory): ScanCategory =>
  ({
    ...category,
    rules: category.rules.map(
      rule =>
        ({
          ...rule,
          pagesAffected: rule.pagesAffected.map(
            page => {
              const { items, ...pageWithoutItems } = page;

              return {
                ...pageWithoutItems,
                itemsCount: page.itemsCount ?? (Array.isArray(items) ? items.length : 0),
                items: Array.isArray(items) ? items.map(toHtmlGroupReference) : items,
              } as any;
            },
          ),
        }) as any,
    ),
  }) as ScanCategory;
*/

const cloneCategoryLight = (category: ScanCategory, includeHtmlGroups: boolean): ScanCategory =>
  ({
    ...category,
    rules: category.rules.map(
      rule =>
        ({
          rule: rule.rule,
          description: rule.description,
          helpUrl: rule.helpUrl,
          conformance: rule.conformance,
          totalItems: rule.totalItems,
          axeImpact: rule.axeImpact,
          ...(includeHtmlGroups && rule.htmlGroups ? { htmlGroups: rule.htmlGroups } : {}),
          pagesAffected: rule.pagesAffected.map(page => ({
            url: page.url,
            pageTitle: page.pageTitle,
            itemsCount: page.itemsCount ?? (Array.isArray((page as any).items) ? (page as any).items.length : 0),
          })),
        }) as any,
    ),
  }) as ScanCategory;

/**
 * Builds the embedded HTML-report payload from the full scan items.
 * Includes htmlGroups for non-passed categories (Group by HTML Element),
 * excludes them from passed to keep payload within browser memory limits.
 */
export const convertItemsToReferences = (source: Pick<AllIssues, 'items'>): ScanItemsLight => {
  return {
    mustFix: cloneCategoryLight(source.items.mustFix, true),
    goodToFix: cloneCategoryLight(source.items.goodToFix, true),
    needsReview: cloneCategoryLight(source.items.needsReview, true),
    passed: cloneCategoryLight(source.items.passed, false),
  };
};
