import { ModelSpec, DropdownChoice } from './AtemModels'
import { AtemState } from 'atem-connection'

export function literal<T> (val: T): T {
    return val
}

export interface SourceInfo {
    id: number
    shortName: string
    longName: string
}

export class AtemInfo {

    public static Offsets = {
        ColorBars: 1000,
        Color: 2000,
        MediaPlayer: 3000,
        Usk: 4000,
        Dsk: 5000,
        SuperSource: 6000,
        Cleanfeed: 7000,
        Output: 8000,
        PgmPrv: 10000
    }

    public static InputIsBlack (input: number): boolean {
        return input === 0
    }

    public static InputIsColorBar (input: number): boolean {
        return input === AtemInfo.Offsets.ColorBars
    }

    public static InputIsColor (input: number): boolean {
        return input >= AtemInfo.Offsets.Color && input < (AtemInfo.Offsets.Color + 1000)
    }

    public static InputIsMediaplayer (input: number): boolean {
        return input >= AtemInfo.Offsets.MediaPlayer && input < (AtemInfo.Offsets.MediaPlayer + 1000)
    }

    public static InputIsMediaplayerKey (input: number): boolean {
        return input >= AtemInfo.Offsets.MediaPlayer && input < (AtemInfo.Offsets.MediaPlayer + 1000) && (input % 2) === 1
    }

    public static InputIsUpstreamKey (input: number): boolean {
        return input >= AtemInfo.Offsets.Usk && input < (AtemInfo.Offsets.Usk + 1000)
    }

    public static InputIsDownstreamKey (input: number): boolean {
        return input >= AtemInfo.Offsets.Dsk && input < (AtemInfo.Offsets.Dsk + 1000)
    }

    public static InputIsSuperSource (input: number): boolean {
        return input >= AtemInfo.Offsets.SuperSource && input < (AtemInfo.Offsets.SuperSource + 1000)
    }

    public static InputIsCleanfeed (input: number): boolean {
        return input >= AtemInfo.Offsets.Cleanfeed && input < (AtemInfo.Offsets.Cleanfeed + 1000)
    }

    public static InputIsOutput (input: number): boolean {
        return input >= AtemInfo.Offsets.Output && input < (AtemInfo.Offsets.Output + 1000)
    }

    public static InputIsProgram (input: number): boolean {
        return input >= AtemInfo.Offsets.PgmPrv && input < (AtemInfo.Offsets.PgmPrv + 1000) && (input % 2) === 0
    }

    public static InputIsPreview (input: number): boolean {
        return input >= AtemInfo.Offsets.PgmPrv && input < (AtemInfo.Offsets.PgmPrv + 1000) && (input % 2) === 1
    }

    public static GetSuportSourceIndex (input: number) {
        return input - AtemInfo.Offsets.SuperSource
    }

    public static GetSourcesListForType (model: ModelSpec, state: AtemState, subset?: 'me' | 'aux' | 'mv') {
        const getSource = (id: number, defShort: string, defLong: string) => {
            const input = state.inputs[id]
            const shortName = input ? input.shortName || defShort : defShort
            const longName = input ? input.longName || defLong : defLong

            return literal<SourceInfo>({
                id,
                shortName,
                longName
            })
        }

        const sources: SourceInfo[] = [
            getSource(0, 'Blck', 'Black'),
            getSource(1000, 'Bars', 'Bars'),
            getSource(2001, 'Col1', 'Color 1'),
            getSource(2002, 'Col2', 'Color 2')
        ]

        for (let i = 0; i < model.SSrc; i++) {
            if (model.SSrc === 1) {
                sources.push(getSource(6000, 'SSrc', 'Super Source'))
            } else {
                sources.push(getSource(6000 + i, `SSc${i + 1}`, `Super Source ${i + 1}`))
            }
        }

        for (let i = 1; i <= model.inputs; i++) {
            sources.push(getSource(i, `In ${i}`, `Input ${i}`))
        }

        for (let i = 1; i <= model.media.players; i++) {
            sources.push(getSource(3000 + i * 10, `MP ${i}`, `Media Player ${i}`))
            sources.push(getSource(3001 + i * 10, `MP${i}K`, `Media Player ${i} Key`))
        }

        if (!subset || subset === 'mv') {
            for (let i = 1; i <= model.auxes; i++) {
                sources.push(getSource(8000 + i, `Aux${i}`, `Auxiliary ${i}`))
            }
        }

        if (!subset || subset === 'mv' || subset === 'aux') {
            for (let i = 1; i <= model.DSKs; i++) {
                sources.push(getSource(7000 + i, `Cln${i}`, `Clean Feed ${i}`))
            }
        }

        for (let i = 1; i <= model.MEs; i++) {
            if (i === 1 && subset === 'me') {
                // Lower ME's can't be referenced by higher
                // We can't do anything beyond ME1 as it is a static list
                continue
            }

            sources.push(getSource(10000 + i * 10, `M${i}PG`, `ME ${i} Program`))
            sources.push(getSource(10000 + i * 10 + 1, `M${i}PV`, `ME ${i} Preview`))
        }

        sources.sort((a, b) => a.id - b.id)
        return sources
    }

    public static SourcesToChoices (sources: SourceInfo[]): DropdownChoice[] {
        return sources.map(s => ({
            id: s.id,
            label: s.longName
        }))
    }
}
