import { YT, YTNodes } from 'youtubei.js';
import { getInnertube } from '.';
import type {
	ChannelContent,
	ChannelContentVideos,
	ChannelOptions,
	ChannelPage,
	Image,
	Video
} from '../model';
import { invidiousItemSchema } from './schema';
import { associateAvatar } from '$lib/thumbnail';

export async function getChannelYTjs(channelId: string): Promise<ChannelPage> {
	const innertube = await getInnertube();

	const innerResults = await innertube.getChannel(channelId);

	let authorBanners: Image[] = [];
	if (
		innerResults.header?.is(YTNodes.PageHeader) &&
		innerResults.header.content?.is(YTNodes.PageHeaderView)
	) {
		authorBanners = innerResults.header.content.banner?.image ?? [];
	}

	if (innerResults.metadata.avatar) await associateAvatar(channelId, innerResults.metadata.avatar);

	const description = innerResults.metadata.description ?? '';

	return {
		type: 'channel',
		allowedRegions: innerResults.metadata.available_countries ?? [],
		tabs: innerResults.tabs.map((tab) => tab.toLowerCase()),
		latestVideos: [],
		isFamilyFriendly: true,
		author: innerResults.metadata.title ?? '',
		authorThumbnails: innerResults.metadata.avatar ?? [],
		authorId: channelId,
		authorBanners,
		joined: 0,
		authorVerified: true,
		totalViews: 0,
		authorUrl: `/channel/${channelId}`,
		subCount: 0,
		autoGenerated: false,
		description,
		descriptionHml: description
	};
}

export function invidiousChannelContentSchema(
	innerResults: YT.Channel | YT.ChannelListContinuation,
	author: string,
	authorId: string
) {
	const videos: Video[] = [];

	let contents;
	if (
		innerResults instanceof YT.Channel &&
		innerResults.current_tab?.content?.is(YTNodes.RichGrid)
	) {
		contents = innerResults.current_tab.content.contents;
	} else if (
		innerResults instanceof YT.ChannelListContinuation &&
		innerResults.contents?.is(YTNodes.AppendContinuationItemsAction)
	) {
		contents = innerResults.contents.contents;
	}

	if (!contents) return videos;

	contents.forEach((item) => {
		if (item.is(YTNodes.RichItem)) {
			const invidiousSchema = invidiousItemSchema(item.content);
			if (invidiousSchema?.type === 'video') {
				invidiousSchema.author = author;
				invidiousSchema.authorId = authorId;
				videos.push(invidiousSchema);
			}
		}
	});

	return videos;
}

function fetchChannelContentVideosWithContinuation(
	innerResults: YT.ChannelListContinuation,
	author: string,
	authorId: string
): () => Promise<ChannelContentVideos> {
	return async () => {
		const continuation = await innerResults.getContinuation();
		return {
			videos: invidiousChannelContentSchema(continuation, author, authorId),
			getContinuation: fetchChannelContentVideosWithContinuation(continuation, author, authorId)
		};
	};
}

async function fetchChannelContentWithContinuation(
	innerResults: YT.Channel | YT.ChannelListContinuation,
	author: string,
	authorId: string
): Promise<ChannelContent> {
	const channelContent: ChannelContent = {
		continuation: innerResults.has_continuation ? 'logicalPlaceholder' : undefined,
		videos: invidiousChannelContentSchema(innerResults, author, authorId)
	};

	if (channelContent.continuation) {
		channelContent.getContinuation = fetchChannelContentVideosWithContinuation(
			innerResults,
			author,
			authorId
		);
	}

	return channelContent;
}

export async function getChannelContentYTjs(
	channelId: string,
	options: ChannelOptions
): Promise<ChannelContent> {
	const innertube = await getInnertube();

	const channel = await innertube.getChannel(channelId);

	const author = channel.metadata.title ?? '';

	let innerResults: YT.Channel | YT.ChannelListContinuation;
	if (options.type === 'videos') {
		innerResults = await channel.getVideos();
	} else if (options.type === 'playlists') {
		innerResults = await channel.getPlaylists();
	} else if (options.type === 'shorts') {
		innerResults = await channel.getShorts();
	} else {
		innerResults = await channel.getLiveStreams();
	}

	return fetchChannelContentWithContinuation(innerResults, author, channelId);
}
