import type { AnimeDetailData, AnimeLibraryItem, AnimeWord, DailyRollup, EpisodeDetailData, EpisodesPerDay, KanjiDetailData, KanjiEntry, MediaDetailData, MediaLibraryItem, MonthlyRollup, NewAnimePerDay, OverviewData, SentenceSearchResult, SessionEvent, SessionSummary, SessionTimelinePoint, StatsAnkiNoteInfo, StatsCoverImagesData, StatsExcludedWord, StreakCalendarDay, TrendsDashboardData, VocabularyEntry, VocabularyOccurrenceEntry, WatchTimePerAnime, WordDetailData, } from './stats-wire'; export type StatsTrendRange = '7d' | '30d' | '90d' | '365d' | 'all'; export type StatsTrendGroupBy = 'day' | 'month'; export type StatsMineMode = 'word' | 'sentence' | 'audio'; export interface StatsSessionKnownWordsTimelinePoint { linesSeen: number; knownWordsSeen: number; totalWordsSeen: number; } export interface StatsKnownWordsSummary { totalUniqueWords: number; knownWordCount: number; } export interface StatsAnilistSearchResult { id: number; episodes: number | null; season: string | null; seasonYear: number | null; description: string | null; coverImage: { large: string | null; medium: string | null } | null; title: { romaji: string | null; english: string | null; native: string | null } | null; } export interface StatsAnilistAssignment { anilistId: number; titleRomaji?: string | null; titleEnglish?: string | null; titleNative?: string | null; episodesTotal?: number | null; description?: string | null; coverUrl?: string | null; } export interface StatsMineCardParams { sourcePath: string; startMs: number; endMs: number; sentence: string; word: string; secondaryText?: string | null; videoTitle: string; mode: StatsMineMode; } export interface StatsMineCardResponse { noteId?: number; error?: string; errors?: string[]; } export interface StatsCoverImagesRequest { animeIds: number[]; videoIds: number[]; } export interface StatsExcludedWordsRequest { words: StatsExcludedWord[]; } export interface StatsVideoWatchedRequest { watched: boolean; } export interface StatsDeleteSessionsRequest { sessionIds: number[]; } export interface StatsAnkiNotesInfoRequest { noteIds: number[]; } export interface StatsOkResponse { ok: true; } export interface StatsErrorResponse { error: string; } export interface StatsAnkiBrowseResponse { result?: number[] | null; error?: string | null; } export interface StatsJsonResponseMap { error: StatsErrorResponse | null; overview: OverviewData; dailyRollups: DailyRollup[]; monthlyRollups: MonthlyRollup[]; sessions: SessionSummary[]; sessionTimeline: SessionTimelinePoint[]; sessionEvents: SessionEvent[]; sessionKnownWordsTimeline: StatsSessionKnownWordsTimelinePoint[]; vocabulary: VocabularyEntry[]; excludedWords: StatsExcludedWord[]; setExcludedWords: StatsOkResponse; wordOccurrences: VocabularyOccurrenceEntry[]; sentenceSearch: SentenceSearchResult[]; kanji: KanjiEntry[]; kanjiOccurrences: VocabularyOccurrenceEntry[]; wordDetail: WordDetailData; kanjiDetail: KanjiDetailData; mediaLibrary: MediaLibraryItem[]; mediaDetail: MediaDetailData; animeLibrary: AnimeLibraryItem[]; animeDetail: AnimeDetailData; animeWords: AnimeWord[]; animeRollups: DailyRollup[]; setVideoWatched: StatsOkResponse; deleteSessions: StatsOkResponse; deleteSession: StatsOkResponse; deleteVideo: StatsOkResponse; anilistSearch: StatsAnilistSearchResult[]; knownWords: string[]; knownWordsSummary: StatsKnownWordsSummary; animeKnownWordsSummary: StatsKnownWordsSummary; mediaKnownWordsSummary: StatsKnownWordsSummary; reassignAnimeAnilist: StatsOkResponse; coverImages: StatsCoverImagesData; episodeDetail: EpisodeDetailData; ankiBrowse: StatsAnkiBrowseResponse; ankiNotesInfo: StatsAnkiNoteInfo[]; mineCard: StatsMineCardResponse; streakCalendar: StreakCalendarDay[]; episodesPerDay: EpisodesPerDay[]; newAnimePerDay: NewAnimePerDay[]; watchTimePerAnime: WatchTimePerAnime[]; trendsDashboard: TrendsDashboardData; } export function statsJson( _key: Key, payload: StatsJsonResponseMap[Key], ): StatsJsonResponseMap[Key] { return payload; } export interface StatsHttpClient { getOverview: () => Promise; getDailyRollups: (limit?: number) => Promise; getMonthlyRollups: (limit?: number) => Promise; getSessions: (limit?: number) => Promise; getSessionTimeline: (id: number, limit?: number) => Promise; getSessionEvents: (id: number, limit?: number, eventTypes?: number[]) => Promise; getSessionKnownWordsTimeline: (id: number) => Promise; getVocabulary: (limit?: number) => Promise; getExcludedWords: () => Promise; setExcludedWords: (words: StatsExcludedWord[]) => Promise; getWordOccurrences: ( headword: string, word: string, reading: string, limit?: number, offset?: number, ) => Promise; searchSentences: ( query: string, limit?: number, searchByHeadword?: boolean, ) => Promise; getKanji: (limit?: number) => Promise; getKanjiOccurrences: ( kanji: string, limit?: number, offset?: number, ) => Promise; getMediaLibrary: () => Promise; getMediaDetail: (videoId: number) => Promise; getAnimeLibrary: () => Promise; getAnimeDetail: (animeId: number) => Promise; getAnimeWords: (animeId: number, limit?: number) => Promise; getAnimeRollups: (animeId: number, limit?: number) => Promise; getAnimeCoverUrl: (animeId: number, retryToken?: number) => string; getCoverImages: (params: StatsCoverImagesRequest) => Promise; getStreakCalendar: (days?: number) => Promise; getEpisodesPerDay: (limit?: number) => Promise; getNewAnimePerDay: (limit?: number) => Promise; getWatchTimePerAnime: (limit?: number) => Promise; getTrendsDashboard: ( range: StatsTrendRange, groupBy: StatsTrendGroupBy, fillEmpty?: boolean, ) => Promise; getWordDetail: (wordId: number) => Promise; getKanjiDetail: (kanjiId: number) => Promise; getEpisodeDetail: (videoId: number) => Promise; setVideoWatched: (videoId: number, watched: boolean) => Promise; deleteSession: (sessionId: number) => Promise; deleteSessions: (sessionIds: number[]) => Promise; deleteVideo: (videoId: number) => Promise; getKnownWords: () => Promise; getKnownWordsSummary: () => Promise; getAnimeKnownWordsSummary: (animeId: number) => Promise; getMediaKnownWordsSummary: (videoId: number) => Promise; searchAnilist: (query: string) => Promise; reassignAnimeAnilist: (animeId: number, info: StatsAnilistAssignment) => Promise; mineCard: (params: StatsMineCardParams) => Promise; ankiBrowse: (noteId: number) => Promise; ankiNotesInfo: (noteIds: number[]) => Promise; }