package mpeg

// ISO/IEC 14496-15 AVC file format, 5.3.3.1.2 Syntax
// ISO_IEC_14496-10 AVC

// TODO: use avcLevels

import (
	"github.com/wader/fq/format"
	"github.com/wader/fq/pkg/decode"
	"github.com/wader/fq/pkg/interp"
	"github.com/wader/fq/pkg/scalar"
)

var avcDCRNALFormat decode.Group

func init() {
	interp.RegisterFormat(decode.Format{
		Name:        format.AVC_DCR,
		Description: "H.264/AVC Decoder Configuration Record",
		DecodeFn:    avcDcrDecode,
		Dependencies: []decode.Dependency{
			{Names: []string{format.AVC_NALU}, Group: &avcDCRNALFormat},
		},
	})
}

var avcProfileNames = scalar.UintMapSymStr{
	// 66: "constrained_baseline_profile", // (CBP, 66 with constraint set 1)
	66:  "baseline_profile",
	88:  "extended_profile",
	77:  "main_profile",
	100: "high_profile",
	//100: "Constrained High Profile", // (100 with constraint set 4 and 5)
	110: "high_10_profile",
	122: "high_422_profile",
	244: "high_444_predictive_profile",
	// 110: "High 10 Intra Profile", // (110 with constraint set 3)
	// 122: "High 4:2:2 Intra Profile", // (122 with constraint set 3)
	// 244: "High 4:4:4 Intra Profile", // (244 with constraint set 3)
	44:  "cavlc_444_intra_profile",
	83:  "scalable_baseline_profile",
	86:  "scalable_high_profile",
	128: "stereo_high_profile",
	134: "mfc_high_profile",
	138: "multiview_depth_high_profile",
	139: "enhanced_multiview_depth_high_profile",
}

// TODO: 1b contraint flag 1?
var avcLevelNames = scalar.UintMapSymStr{
	10: "1",
	//10:  "1b"
	11: "1.1",
	12: "1.2",
	13: "1.3",
	20: "2",
	21: "2.1",
	22: "2.2",
	30: "3",
	31: "3.1",
	32: "3.2",
	40: "4",
	41: "4.1",
	42: "4.2",
	50: "5",
	51: "5.1",
	52: "5.2",
	60: "6",
	61: "6.1",
	62: "6.2",
}

// type avcLevel struct {
// 	Name         string
// 	MaxMBPS      uint64
// 	MaxFS        uint64
// 	MaxDpbMbs    uint64
// 	MaxBR        uint64
// 	MaxCPB       uint64
// 	MaxVmvR      uint64
// 	MinCR        uint64
// 	MaxMvsPer2Mb uint64
// }

// TODO: 1b contraint flag 1?
// var avcLevels = map[uint64]avcLevel{
// 	10: {"1", 1485, 99, 396, 64, 175, 64, 2, 0},
// 	//10:  {"1b", 1485, 99, 396, 128, 350, 64, 2, 0}, //
// 	11: {"1.1", 3000, 396, 900, 192, 500, 128, 2, 0},
// 	12: {"1.2", 6000, 396, 2376, 384, 1000, 128, 2, 0},
// 	13: {"1.3", 11880, 396, 2376, 768, 2000, 128, 2, 0},
// 	20: {"2", 11880, 396, 2376, 2000, 2000, 128, 2, 0},
// 	21: {"2.1", 19800, 792, 4752, 4000, 4000, 256, 2, 0},
// 	22: {"2.2", 20250, 1620, 8100, 4000, 4000, 256, 2, 0},
// 	30: {"3", 40500, 1620, 8100, 10000, 10000, 256, 2, 32},
// 	31: {"3.1", 108000, 3600, 18000, 14000, 14000, 512, 4, 16},
// 	32: {"3.2", 216000, 5120, 20480, 20000, 20000, 512, 4, 16},
// 	40: {"4", 245760, 8192, 32768, 20000, 25000, 512, 4, 16},
// 	41: {"4.1", 245760, 8192, 32768, 50000, 62500, 512, 2, 16},
// 	42: {"4.2", 522240, 8704, 34816, 50000, 62500, 512, 2, 16},
// 	50: {"5", 589824, 22080, 110400, 135000, 135000, 512, 2, 16},
// 	51: {"5.1", 983040, 36864, 184320, 240000, 240000, 512, 2, 16},
// 	52: {"5.2", 2073600, 36864, 184320, 240000, 240000, 512, 2, 16},
// 	60: {"6", 4177920, 139264, 696320, 240000, 240000, 8192, 2, 16},
// 	61: {"6.1", 8355840, 139264, 696320, 480000, 480000, 8192, 2, 16},
// 	62: {"6.2", 16711680, 139264, 696320, 800000, 800000, 8192, 2, 16},
// }

func avcDcrParameterSet(d *decode.D, numParamSets uint64) {
	for i := uint64(0); i < numParamSets; i++ {
		d.FieldStruct("set", func(d *decode.D) {
			paramSetLen := d.FieldU16("length")
			d.FieldFormatLen("nal", int64(paramSetLen)*8, avcDCRNALFormat, nil)
		})
	}
}

func avcDcrDecode(d *decode.D, _ any) any {
	d.FieldU8("configuration_version")
	d.FieldU8("profile_indication", avcProfileNames)
	d.FieldU8("profile_compatibility")
	d.FieldU8("level_indication", avcLevelNames)
	d.FieldU6("reserved0")
	lengthSize := d.FieldU2("length_size", scalar.UintActualAdd(1))
	d.FieldU3("reserved1")
	numSeqParamSets := d.FieldU5("num_of_sequence_parameter_sets")
	d.FieldArray("sequence_parameter_sets", func(d *decode.D) {
		avcDcrParameterSet(d, numSeqParamSets)
	})
	numPicParamSets := d.FieldU8("num_of_picture_parameter_sets")
	d.FieldArray("picture_parameter_sets", func(d *decode.D) {
		avcDcrParameterSet(d, numPicParamSets)
	})

	if d.BitsLeft() > 0 {
		d.FieldRawLen("data", d.BitsLeft())
	}

	// TODO:
	// Compatible extensions to this record will extend it and will not change the configuration version code. Readers
	// should be prepared to ignore unrecognized data beyond the definition of the data they understand (e.g. after
	// the parameter sets in this specification).

	// TODO: something wrong here, seen files with profileIdc = 100 with no bytes after picture_parameter_sets
	// https://github.com/FFmpeg/FFmpeg/blob/069d2b4a50a6eb2f925f36884e6b9bd9a1e54670/libavcodec/h264_ps.c#L333

	return format.AvcDcrOut{LengthSize: lengthSize}
}
