import { components } from '@/lib/gen';
import { ClientEntity } from '@/lib/typeUtils';

import { Clip } from './clipStore';
import { RootStore, Substore } from './rootStore';
import { makeAutoObservableSubstore } from './utils';

export enum StyleType {
  Featured = 'featured',
}

export enum SectionType {
  Banner = 'banner',
  Playlist = 'playlist',
  PlaylistList = 'playlist_list',
  StyleList = 'style_list',
  UserList = 'user_list',
  PersonaList = 'persona_list',
  FeaturedFeed = 'featured_feed',
  Shortcut = 'shortcut',
  Hooks = 'hooks',
  ContestList = 'contest_list',
}

export type DiscoverSection = NonNullable<
  components['schemas']['DiscoverResp']['sections']
>[number];

export type DiscoverCarouselSection = Extract<
  DiscoverSection,
  {
    section_type?:
      | `${SectionType.Playlist}`
      | `${SectionType.PlaylistList}`
      | `${SectionType.StyleList}`
      | `${SectionType.UserList}`
      | `${SectionType.PersonaList}`
      | `${SectionType.Hooks}`
      | `${SectionType.ContestList}`;
  }
>;

export type DiscoverFeaturedFeedSection = Extract<
  DiscoverSection,
  { section_type?: `${SectionType.FeaturedFeed}` }
>;

export type DiscoverSectionItemEntity<
  T extends DiscoverSection['section_type'] = DiscoverSection['section_type'],
> = ClientEntity<
  Extract<DiscoverSection, { section_type?: T }>['items'][number]
>;

export class DiscoverStore implements Substore {
  discoverSections: DiscoverSection[] = [];
  currentIndex = 0;
  totalSections = 0;
  readonly root: RootStore;
  get apiClient() {
    return this.root.apiClient;
  }
  // DO NOT ADD INIT LOGIC IN constructor. this will run on every page! considering adding any it in the component init logic instead
  constructor(root: RootStore) {
    this.root = root;
    makeAutoObservableSubstore(this);
  }

  sectionUpdate = async ({
    sectionName,
    sectionContent = null,
    secondarySectionContent = null,
    page = 1,
    sectionSize = null,
    disableShuffle = false,
    concatSections = false,
  }: {
    sectionName: string;
    sectionContent?: string | null;
    secondarySectionContent?: string | null;
    page?: number;
    sectionSize?: number | null;
    disableShuffle?: boolean;
    concatSections?: boolean;
  }) => {
    const { data } = await this.apiClient.POST('/api/discover/', {
      body: {
        start_index: 0,
        page_size: 1,
        section_name: sectionName,
        section_content: sectionContent,
        secondary_section_content: secondarySectionContent,
        page: page,
        section_size: sectionSize,
        disable_shuffle: disableShuffle,
      },
    });
    if (!data || !data.sections) return;

    // update clips to the clip state for contexts
    const clipsToUpdate = [] as Clip[];
    data.sections.forEach((section) => {
      if (section.section_type === 'playlist') {
        clipsToUpdate.push(...section.items);
      }
    });
    this.root.clips.updateClips(clipsToUpdate);

    if (data.sections.length && concatSections) {
      this.discoverSections = this.discoverSections.concat(data.sections);
    }
    return data;
  };

  updateFeaturedFeedClips = ({
    feedSections,
    clipsToUpdate,
  }: {
    feedSections: components['schemas']['FeaturedFeedSchema'][];
    clipsToUpdate: Clip[];
  }) => {
    if (!feedSections) return;
    feedSections.forEach((feedSection) => {
      if (!feedSection.items) return;

      feedSection.items.forEach((item) => {
        // for you + trending
        if (item.entity_type === 'song_schema') {
          clipsToUpdate.push(item);
        } else if (
          // following feed song items
          item.entity_type === 'following_feed_item_schema' &&
          item.activity_type === 'publish_song'
        ) {
          if (item.clip_schema) {
            clipsToUpdate.push(item.clip_schema);
          }
        }
      });
    });
  };

  fetch = async (
    start: number,
    size: number,
    section_name: string | null = null,
    section_content: string | null = null,
    secondary_section_content: string | null = null,
    product: 'archive' | null = null
  ) => {
    const { data } = await this.apiClient.POST('/api/discover/', {
      body: {
        start_index: start,
        page_size: size,
        section_name: section_name,
        section_content: section_content,
        secondary_section_content: secondary_section_content,
        product: product,
      },
    });
    if (!data || !data.sections) return;
    // update clips to the clip state for contexts
    const clipsToUpdate = [] as Clip[];
    data.sections.forEach((section) => {
      if (section.section_type === 'playlist') {
        clipsToUpdate.push(...section.items);
      }
    });
    this.root.clips.updateClips(clipsToUpdate);

    if (!product) {
      this.discoverSections = this.discoverSections.concat(data.sections);
    }
    this.totalSections = data.total_sections;
    this.currentIndex = this.currentIndex + size;
    return data;
  };
}
