import { MediaStreamType } from '@jellyfin/sdk/lib/generated-client/models/media-stream-type';
import { VideoType } from '@jellyfin/sdk/lib/generated-client/models/video-type';
import type { MediaStream } from '@jellyfin/sdk/lib/generated-client/models/media-stream';
import itemHelper from 'components/itemHelper';
import datetime from 'scripts/datetime';
import globalize from 'lib/globalize';

import type { ItemDto } from 'types/base/models/item-dto';
import type { MiscInfo } from 'types/mediaInfoItem';
import type { NullableString } from 'types/base/common/shared/types';
import type { MediaInfoStatsOpts } from './type';

const getResolution = (label: string, isInterlaced?: boolean) =>
    isInterlaced ? `${label}i` : label;

const getResolutionText = (
    showResolutionInfo: boolean,
    stream: MediaStream
) => {
    const { Width, Height, IsInterlaced } = stream;

    if (showResolutionInfo && Width && Height) {
        switch (true) {
            case Width >= 3800 || Height >= 2000:
                return '4K';
            case Width >= 2500 || Height >= 1400:
                return getResolution('1440p', IsInterlaced);
            case Width >= 1800 || Height >= 1000:
                return getResolution('1080p', IsInterlaced);
            case Width >= 1200 || Height >= 700:
                return getResolution('720p', IsInterlaced);
            case Width >= 700 || Height >= 400:
                return getResolution('480p', IsInterlaced);
            default:
                return null;
        }
    }

    return null;
};

const getAudoChannelText = (
    showAudoChannelInfo: boolean,
    stream: MediaStream
) => {
    const { Channels } = stream;

    if (showAudoChannelInfo && Channels) {
        switch (true) {
            case Channels === 8:
                return '7.1';
            case Channels === 7:
                return '6.1';
            case Channels === 6:
                return '5.1';
            case Channels === 2:
                return '2.0';
            default:
                return null;
        }
    }

    return null;
};

function getAudioStreamForDisplay(item: ItemDto) {
    const mediaSource = (item.MediaSources || [])[0] || {};

    return (
        (mediaSource.MediaStreams || []).filter((i) => {
            return (
                i.Type === MediaStreamType.Audio
                && (i.Index === mediaSource.DefaultAudioStreamIndex
                    || mediaSource.DefaultAudioStreamIndex == null)
            );
        })[0] || {}
    );
}

function getVideoStreamForDisplay(item: ItemDto) {
    const mediaSource = (item.MediaSources || [])[0] || {};

    return (
        (mediaSource.MediaStreams || []).filter((i) => {
            return i.Type === MediaStreamType.Video;
        })[0] || {}
    );
}

function addVideoType(
    showVideoTypeInfo: boolean,
    itemVideoType: VideoType | undefined,
    addMiscInfo: (val: MiscInfo) => void
): void {
    if (showVideoTypeInfo) {
        if (itemVideoType === VideoType.Dvd) {
            addMiscInfo({ type: 'mediainfo', text: 'Dvd' });
        }

        if (itemVideoType === VideoType.BluRay) {
            addMiscInfo({ type: 'mediainfo', text: 'BluRay' });
        }
    }
}

function addResolution(
    showResolutionInfo: boolean,
    videoStream: MediaStream,
    addMiscInfo: (val: MiscInfo) => void
): void {
    const resolutionText = getResolutionText(showResolutionInfo, videoStream);

    if (resolutionText) {
        addMiscInfo({ type: 'mediainfo', text: resolutionText });
    }
}

function addVideoStreamCodec(
    showVideoCodecInfo: boolean,
    videoStreamCodec: NullableString,
    addMiscInfo: (val: MiscInfo) => void
): void {
    if (showVideoCodecInfo && videoStreamCodec) {
        addMiscInfo({ type: 'mediainfo', text: videoStreamCodec });
    }
}

function addAudoChannel(
    showAudoChannelInfo: boolean,
    audioStream: MediaStream,
    addMiscInfo: (val: MiscInfo) => void
): void {
    const audioChannelText = getAudoChannelText(
        showAudoChannelInfo,
        audioStream
    );

    if (audioChannelText) {
        addMiscInfo({ type: 'mediainfo', text: audioChannelText });
    }
}

function addAudioStreamCodec(
    showAudioStreamCodecInfo: boolean,
    audioStream: MediaStream,
    addMiscInfo: (val: MiscInfo) => void
): void {
    const audioCodec = (audioStream.Codec || '').toLowerCase();

    if (showAudioStreamCodecInfo) {
        if (
            (audioCodec === 'dca' || audioCodec === 'dts')
            && audioStream?.Profile
        ) {
            addMiscInfo({ type: 'mediainfo', text: audioStream.Profile });
        } else if (audioStream?.Codec) {
            addMiscInfo({ type: 'mediainfo', text: audioStream.Codec });
        }
    }
}

function addDateAdded(
    showDateAddedInfo: boolean,
    item: ItemDto,
    addMiscInfo: (val: MiscInfo) => void
): void {
    if (
        showDateAddedInfo
        && item.DateCreated
        && itemHelper.enableDateAddedDisplay(item)
    ) {
        const dateCreated = datetime.parseISO8601Date(item.DateCreated);
        addMiscInfo({
            type: 'added',
            text: globalize.translate(
                'AddedOnValue',
                `${datetime.toLocaleDateString(
                    dateCreated
                )} ${datetime.getDisplayTime(dateCreated)}`
            )
        });
    }
}

interface UseMediaInfoStatsProps extends MediaInfoStatsOpts {
    item: ItemDto;
}

function useMediaInfoStats({
    item,
    showVideoTypeInfo = false,
    showResolutionInfo = false,
    showVideoStreamCodecInfo = false,
    showAudoChannelInfo = false,
    showAudioStreamCodecInfo = false,
    showDateAddedInfo = false
}: UseMediaInfoStatsProps) {
    const miscInfo: MiscInfo[] = [];

    const addMiscInfo = (val: MiscInfo) => {
        if (val) {
            miscInfo.push(val);
        }
    };

    const videoStream = getVideoStreamForDisplay(item);

    const audioStream = getAudioStreamForDisplay(item);

    addVideoType(showVideoTypeInfo, item.VideoType, addMiscInfo);

    addResolution(showResolutionInfo, videoStream, addMiscInfo);

    addVideoStreamCodec(
        showVideoStreamCodecInfo,
        videoStream.Codec,
        addMiscInfo
    );

    addAudoChannel(showAudoChannelInfo, audioStream, addMiscInfo);

    addAudioStreamCodec(showAudioStreamCodecInfo, audioStream, addMiscInfo);

    addDateAdded(showDateAddedInfo, item, addMiscInfo);

    return miscInfo;
}

export default useMediaInfoStats;
