package data

import (
	"code.ur.gs/lupine/ordoor/internal/util/asciiscan"
)

type ActionPointEnum int
type SettingEnum int
type TransitionFrameEnum int
type SquadTypeEnum int   // just for the multiplayer choose units menu
type VehicleTypeEnum int // just for the multiplayer choose units screen
type OptionEnum int      // differs from settings in that these are defaults changeable from the UI
type SpellEnum int
type AIPriorityEnum int // FIXME: no idea what this is for
type RngRangeEnum int

// VEHICLE_WALK_TRANSITION_FRAME entries

const (
	APCastSpell           ActionPointEnum = 0
	APWalk                                = 1
	APRun                                 = 2
	APTurn                                = 3
	APCrouch                              = 4
	APStand                               = 5
	APOpenDoor                            = 6
	APDropItem                            = 7
	APPickupItem                          = 8
	APThrowItem                           = 9
	APUseMedikit                          = 10
	APUseScanner                          = 11
	APJump                                = 12
	APThrowGrenade                        = 13
	APHalfTurn                            = 14
	APToClearJammedWeapon                 = 15
	APHandToHandRound                     = 16
	APToUseSwitch                         = 17
	APToUseKey                            = 18
	APToBoardDisembark                    = 19
	APWhenOnFire                          = 20
	APWhenBroken                          = 21
	APMax                                 = 22

	SettingOccasionalSoundPercent            SettingEnum = 0
	SettingOccasionalMovementSound                       = 1
	SettingFullJumpFuel                                  = 2
	SettingMaxJumpDistance                               = 3
	SettingFlyFramesPerCell                              = 4
	SettingPowerArmorRating                              = 5
	SettingTerminatorArmorRating                         = 6
	SettingBloodThirsterArmorRating                      = 7
	SettingDemonicArmorRating                            = 8
	SettingPrimitiveArmorRating                          = 9
	SettingHorrorArmorRating                             = 10
	SettingArmorDice                                     = 11
	SettingJumpPixelsPerFrame                            = 12
	SettingCharacterAnimationDelay                       = 13
	SettingVehicleAnimationDelay                         = 14
	SettingLoopingEffectsDelay                           = 15
	SettingFireAnimationDelay                            = 16
	SettingCharacterFireTransparency                     = 17
	SettingMissileDrawOffset                             = 18 // pixels per missing piece
	SettingWeaponJamPercent                              = 19 // to two decimal places
	SettingScanFrequency                                 = 20
	SettingCoverSearchRadius                             = 21
	SettingDialogAutoCloseTime                           = 22
	SettingPointBlankBallisticSkillBonus                 = 23
	SettingPointBlankRange                               = 24
	SettingMinimumOverwatchShotPercent                   = 25
	SettingMultipleSekectDragTolerance                   = 26
	SettingStandingGuardPostRadius                       = 27
	SettingMaxDemonFlyDistance                           = 28
	SettingSpellLoopingVolume                            = 29 // percentage, 0 decimal places
	SettingPercentOfChaosInSecondaryQuadrant             = 30
	SettingNumberOfRandomCrates                          = 31
	SettingMax                                           = 32

	TFDeletedVehicle   TransitionFrameEnum = 0
	TFUltraRhino                           = 1
	TFUltraPredator                        = 2
	TFUltraLandSpeeder                     = 3
	TFUltraDreadnought                     = 4
	TFChaosRhino                           = 5
	TFChaosPredator                        = 6
	TFChaosDreadnought                     = 7
	TFMax                                  = 8

	SquadTerminator        SquadTypeEnum = 0
	SquadTactical                        = 1
	SquadAssault                         = 2
	SquadDevastator                      = 3
	SquadChaos                           = 4
	SquadChaosKhorne                     = 5
	SquadChaosTerminator                 = 6
	SquadChaosCultise                    = 7
	SquadLibrarian                       = 8
	SquadTechmarine                      = 9
	SquadApothecary                      = 10
	SquadChaplain                        = 11
	SquadCaptain                         = 12
	SquadChaosLord                       = 13
	SquadChaosChaplain                   = 14
	SquadChaosSorcerer                   = 15
	SauadChaosBlodThirster               = 16
	SquadChaosBlootLetter                = 17
	SquadChaosFleshHound                 = 18
	SquadChaosLordOfChange               = 19
	SquadChaosFlamer                     = 20
	SquadChaosPinkHorror                 = 21
	SquadChaosBlueHorror                 = 22
	SquadMax                             = 23

	VehicleUltraRhino       VehicleTypeEnum = 0
	VehicleUltraPredator                    = 1
	VehicleUltraLandSpeeder                 = 2
	VehicleUltraDreadnought                 = 3
	VehicleChaosRhino                       = 4
	VehicleChaosPredator                    = 5
	VehicleChaosDreadnought                 = 6
	VehicleMax                              = 7

	OptionMovies               OptionEnum = 0
	OptionMusic                           = 1
	OptionCombatVoices                    = 2
	OptionGrid                            = 3
	OptionShowPaths                       = 4
	OptionPointSave                       = 5
	OptionAutoCutLevel                    = 6
	OptionShowUnitAnimations              = 7
	OptionCombatResolution                = 8
	OptionMusicVolume                     = 9  // percentage, 0df
	OptionSoundEffectsVolume              = 10 // percentage, 0df
	OptionUnitAnimationSpeed              = 11 // percentage, 0df, see CHARCTER ANIMATION DELAY / VEHICLE ANIMATION DELAY for worst case value
	OptionEffectAnimationSpeed            = 12 // percentage, 0d, see LOOPING_EFFECTS_DELAY for worst case value
	OptionMax                             = 13

	SpellHellfire           SpellEnum = 0
	SpellLightningArc                 = 1
	SpellGate                         = 2
	SpellAssail                       = 3
	SpellDisplacement                 = 4
	SpellMachineCurse                 = 5
	SpellScan                         = 6
	SpellQuickening                   = 7
	SpellStrengthOfMind               = 8
	SpellSmite                        = 9
	SpellIronArm                      = 10
	SpellSalamandar                   = 11
	SpellTeleport                     = 12
	SpellPsychicShield                = 13
	SpellDestroyDemon                 = 14
	SpellHolocaust                    = 15
	SpellScourge                      = 16
	SpellPurge                        = 17
	SpellAuraOfFire                   = 18
	SpellVortex                       = 19
	SpellStormOfWrath                 = 20
	SpellAuraOfFortitude              = 21
	SpellPinkFireOfTzeentch           = 22
	SpellBoltOfChange                 = 23
	SpellTzeentchFireStore            = 24
	SpellMax                          = 25

	AIPrioritySpecialCharacter = 0
	AIPriorityVehicle          = 1
	AIPriorityTerminator       = 2
	AIPriorityHeavyWeapon      = 3
	AIPriorityRegular          = 4
	AIPriorityCultist          = 5
	AIPriorityMax              = 6

	RngRangeVehicleHillHeight           RngRangeEnum = 0
	RngRangeVehicleHillWidth                         = 1
	RngRangeVehicleHillDensity                       = 2
	RngRangeVehicleLargeObjectDensity                = 3
	RngRangeVehicleSmallObjectDensity                = 4
	RngRangeNoVehicleHillHeight                      = 5
	RngRangeNoVehicleHillWidth                       = 6
	RngRangeNoVehicleHillDensity                     = 7
	RngRangeNoVehicleLargeObjectDensity              = 8
	RngRangeNoVehicleSmallObjectDensity              = 9
	RngRangeMax                                      = 10

	// FIXME: is this really a hardcoded value?
	NumCampaignScenarios = 15
)

type Generic struct {
	ActionPoints                map[ActionPointEnum]int
	Settings                    map[SettingEnum]int
	VehicleWalkTransitionFrames map[TransitionFrameEnum]CompassPoints
	MPChooseUnitSquadLimits     map[SquadTypeEnum]int

	// I'm assuming this is to do with MP becauses squads are. I could be wrong.
	MPChooseVehicleLimits map[VehicleTypeEnum]int

	Options map[OptionEnum]int

	CampaignMaps           []string
	CampaignEndMissionWavs []string

	AICoherentForce                       int               // Range that defnines a coherent for for the AI. No idea
	AISpellDeltaPriorityWeights           map[SpellEnum]int // AI delta priority weights for each spell
	AIPriority                            map[AIPriorityEnum]int
	AICommandInfiniteLoopCounterWatermark int // Messing with this can cripple the API...

	RngRanges map[RngRangeEnum]Range
}

// TODO: consume these values from the file
func LoadGeneric(filename string) (*Generic, error) {
	s, err := asciiscan.New(filename)
	if err != nil {
		return nil, err
	}
	defer s.Close()

	out := &Generic{
		ActionPoints:                make(map[ActionPointEnum]int),
		Settings:                    make(map[SettingEnum]int),
		VehicleWalkTransitionFrames: make(map[TransitionFrameEnum]CompassPoints),
		MPChooseUnitSquadLimits:     make(map[SquadTypeEnum]int),
		MPChooseVehicleLimits:       make(map[VehicleTypeEnum]int),
		Options:                     make(map[OptionEnum]int),
		AISpellDeltaPriorityWeights: make(map[SpellEnum]int),
		AIPriority:                  make(map[AIPriorityEnum]int),
		RngRanges:                   make(map[RngRangeEnum]Range),
	}

	// Various action point values, first to last
	for ap := ActionPointEnum(0); ap < APMax; ap++ {
		val, err := s.ConsumeInt()
		if err != nil {
			return nil, err
		}

		out.ActionPoints[ap] = val
	}

	// Other miscellaneous data fields, first to last
	for setting := SettingEnum(0); setting < SettingMax; setting++ {
		val, err := s.ConsumeInt()
		if err != nil {
			return nil, err
		}

		out.Settings[setting] = val
	}

	// Vehicle walk transition frames. Whatever they are.
	for tf := TransitionFrameEnum(0); tf < TFMax; tf++ {
		val, err := consumeCompassPoints(s)
		if err != nil {
			return nil, err
		}

		out.VehicleWalkTransitionFrames[tf] = val
	}

	for st := SquadTypeEnum(0); st < SquadMax; st++ {
		val, err := s.ConsumeInt()
		if err != nil {
			return nil, err
		}

		out.MPChooseUnitSquadLimits[st] = val
	}

	for vt := VehicleTypeEnum(0); vt < VehicleMax; vt++ {
		val, err := s.ConsumeInt()
		if err != nil {
			return nil, err
		}

		out.MPChooseVehicleLimits[vt] = val
	}

	for op := OptionEnum(0); op < OptionMax; op++ {
		val, err := s.ConsumeInt()
		if err != nil {
			return nil, err
		}

		out.Options[op] = val
	}

	for i := 0; i < NumCampaignScenarios; i++ {
		val, err := s.ConsumeString()
		if err != nil {
			return nil, err
		}

		out.CampaignMaps = append(out.CampaignMaps, val)
	}

	for i := 0; i < NumCampaignScenarios; i++ {
		val, err := s.ConsumeString()
		if err != nil {
			return nil, err
		}

		// FIXME: "none" is a special-case value here
		out.CampaignEndMissionWavs = append(out.CampaignEndMissionWavs, val)
	}

	out.AICoherentForce, err = s.ConsumeInt()
	if err != nil {
		return nil, err
	}

	for sp := SpellEnum(0); sp < SpellMax; sp++ {
		val, err := s.ConsumeInt()
		if err != nil {
			return nil, err
		}

		out.AISpellDeltaPriorityWeights[sp] = val
	}

	for ai := AIPriorityEnum(0); ai < AIPriorityMax; ai++ {
		val, err := s.ConsumeInt()
		if err != nil {
			return nil, err
		}

		out.AIPriority[ai] = val
	}

	out.AICommandInfiniteLoopCounterWatermark, err = s.ConsumeInt()
	if err != nil {
		return nil, err
	}

	for rg := RngRangeEnum(0); rg < RngRangeMax; rg++ {
		val, err := consumeRange(s)
		if err != nil {
			return nil, err
		}

		out.RngRanges[rg] = val
	}

	return out, nil
}
