import { computed, makeObservable } from 'mobx';
import { FiltersMap, KeyedItem } from '@wix/bex-core';
import { TableState } from '../../state';
import { RenderSection, Section } from '../CollectionSectionHeader';

const SECTION_PREFIX = '$$$wix-patterns-sections$$$-';
const INVISIBLE_ROW_ID = `${SECTION_PREFIX}invisible`;

export class TableSectionsState<T, F extends FiltersMap> {
  table: TableState<T, F>;
  renderSection: RenderSection<T>;

  constructor(table: TableState<T, F>, renderSection: RenderSection<T>) {
    this.table = table;
    this.renderSection = renderSection;
    makeObservable(this, {
      sectionsKeyedItems: computed,
      sectionCounts: computed,
    });
  }

  private generateSectionId(firstItemId: string): string {
    return `${SECTION_PREFIX}${firstItemId}`;
  }

  private get computeSectionData(): {
    counts: Map<string, { count: number; isComplete: boolean }>;
    keyedItems: KeyedItem<T>[];
  } {
    const counts = new Map<string, { count: number; isComplete: boolean }>();
    const keyedItems: KeyedItem<T>[] = [];

    if (this.table.keyedItems.length === 0) {
      return { counts, keyedItems };
    }

    // Add invisible row for design purposes
    keyedItems.push({
      id: INVISIBLE_ROW_ID,
      key: INVISIBLE_ROW_ID,
      item: this.table.keyedItems[0].item,
      index: 0,
      pageIndex: 0,
      indexWithinPage: 0,
    });

    let currentSectionId: string | null = null;
    let currentSectionIndex: number = 0;
    let currentHeaderId: string | null = null;
    let count = 0;

    for (const keyedItem of this.table.keyedItems) {
      const section = this.renderSection(keyedItem.item);
      const sectionId = section.id;

      if (sectionId !== currentSectionId) {
        // Store count for previous section
        if (currentHeaderId) {
          counts.set(currentHeaderId, { count, isComplete: true });
        }

        // Start new section
        currentSectionId = sectionId;
        currentHeaderId = this.generateSectionId(
          `${sectionId}@${currentSectionIndex}`,
        );
        currentSectionIndex++;
        count = 1;

        // Add section header to keyed items
        const sectionKeyedItem: KeyedItem<T> = {
          id: currentHeaderId,
          key: currentHeaderId,
          item: keyedItem.item,
          index: keyedItems.length,
          pageIndex: 0,
          indexWithinPage: keyedItems.length,
        };
        keyedItems.push(sectionKeyedItem);
      } else {
        count++;
      }

      // Add the actual data item
      keyedItems.push(keyedItem);
    }

    // Handle last section
    if (currentHeaderId) {
      const isLastSectionComplete = this.table.collection.fetchedLastPage;
      counts.set(currentHeaderId, { count, isComplete: isLastSectionComplete });
    }

    return { counts, keyedItems };
  }

  get sectionCounts(): Map<string, { count: number; isComplete: boolean }> {
    return this.computeSectionData.counts;
  }

  get sectionsKeyedItems(): KeyedItem<T>[] {
    return this.computeSectionData.keyedItems;
  }

  getSectionWithCount(
    sectionKeyedItem: KeyedItem<T>,
  ): Section & { count: number; hasMore: boolean } {
    const section = this.renderSection(sectionKeyedItem.item);
    const headerId = sectionKeyedItem.id;
    const sectionData = headerId
      ? this.sectionCounts.get(headerId) || { count: 0, isComplete: true }
      : { count: 0, isComplete: true };

    return {
      ...section,
      count: sectionData.count,
      hasMore: !sectionData.isComplete,
    };
  }

  isSectionRow(keyedItem: KeyedItem<T>): boolean {
    return keyedItem.id.startsWith(SECTION_PREFIX);
  }

  isInvisibleRow(keyedItem: KeyedItem<T>): boolean {
    return keyedItem.id === INVISIBLE_ROW_ID;
  }
}
