package calc

import "math"

// FeeBracket defines one bracket in a fee schedule.
// [upperBound, stepSize, gkgIncrement, rvgIncrement]
type FeeBracket struct {
	UpperBound   float64
	StepSize     float64
	GKGIncrement float64
	RVGIncrement float64
}

// FeeSchedule defines a versioned fee schedule.
type FeeSchedule struct {
	Label     string
	ValidFrom string
	Brackets  []FeeBracket
}

// InstanceMeta defines the fee factors for a court instance.
type InstanceMeta struct {
	Key                string
	Label              string
	LabelEN            string
	CourtFeeFactor     float64
	FeeBasis           string // "GKG", "PatKostG", "fixed"
	FixedCourtFee      float64
	RAVGFactor         float64
	RATGFactor         float64
	PAVGFactor         float64
	PATGFactor         float64
	HasPatentAttorneys bool
}

// UPCFeeBracket maps a max dispute value to a court fee.
type UPCFeeBracket struct {
	MaxValue *float64 // nil = unlimited
	Fee      float64
}

// UPCRecoverableCost maps a max dispute value to a recoverable cost ceiling.
type UPCRecoverableCost struct {
	MaxValue *float64 // nil = unlimited
	Ceiling  float64
}

// UPCFeeSchedule defines UPC court fees for a version.
type UPCFeeSchedule struct {
	Label            string
	FixedInfringement float64
	FixedRevocation   float64
	ValueBased       []UPCFeeBracket
	RecoverableCosts []UPCRecoverableCost
	SMEReduction     float64 // 0.4 = 40% reduction
}

// EPAFee defines a fixed EPA proceeding fee.
type EPAFee struct {
	Key     string
	Label   string
	LabelEN string
	Fee     float64
	SMEFee  float64 // 0 if no SME discount
}

// FeeSchedules contains all GKG/RVG bracket tables by version.
var FeeSchedules = map[string]FeeSchedule{
	"2005": {
		Label:     "GKG/RVG 2006-09-01",
		ValidFrom: "2006-09-01",
		Brackets: []FeeBracket{
			{300, 300, 25, 25},
			{1500, 300, 10, 20},
			{5000, 500, 8, 28},
			{10000, 1000, 15, 37},
			{25000, 3000, 23, 40},
			{50000, 5000, 29, 72},
			{200000, 15000, 100, 77},
			{500000, 30000, 150, 118},
			{math.Inf(1), 50000, 150, 150},
		},
	},
	"2013": {
		Label:     "GKG/RVG 2013-08-01",
		ValidFrom: "2013-08-01",
		Brackets: []FeeBracket{
			{500, 300, 35, 45},
			{2000, 500, 18, 35},
			{10000, 1000, 19, 51},
			{25000, 3000, 26, 46},
			{50000, 5000, 35, 75},
			{200000, 15000, 120, 85},
			{500000, 30000, 179, 120},
			{math.Inf(1), 50000, 180, 150},
		},
	},
	"2021": {
		Label:     "GKG/RVG 2021-01-01",
		ValidFrom: "2021-01-01",
		Brackets: []FeeBracket{
			{500, 300, 38, 49},
			{2000, 500, 20, 39},
			{10000, 1000, 21, 56},
			{25000, 3000, 29, 52},
			{50000, 5000, 38, 81},
			{200000, 15000, 132, 94},
			{500000, 30000, 198, 132},
			{math.Inf(1), 50000, 198, 165},
		},
	},
	"2025": {
		Label:     "GKG/RVG 2025-06-01",
		ValidFrom: "2025-06-01",
		Brackets: []FeeBracket{
			{500, 300, 40, 51.5},
			{2000, 500, 21, 41.5},
			{10000, 1000, 22.5, 59.5},
			{25000, 3000, 30.5, 55},
			{50000, 5000, 40.5, 86},
			{200000, 15000, 140, 99.5},
			{500000, 30000, 210, 140},
			{math.Inf(1), 50000, 210, 175},
		},
	},
}

// FeeScheduleAliases maps alias names to actual schedule versions.
var FeeScheduleAliases = map[string]string{
	"Aktuell": "2025",
}

// DEInfringementInstances lists the court instances for DE patent infringement.
var DEInfringementInstances = []InstanceMeta{
	{
		Key:                "LG",
		Label:              "LG (Verletzung 1. Instanz)",
		LabelEN:            "Regional Court (Infringement 1st Instance)",
		CourtFeeFactor:     3.0,
		FeeBasis:           "GKG",
		RAVGFactor:         1.3,
		RATGFactor:         1.2,
		PAVGFactor:         1.3,
		PATGFactor:         1.2,
		HasPatentAttorneys: true,
	},
	{
		Key:                "OLG",
		Label:              "OLG (Berufung)",
		LabelEN:            "Higher Regional Court (Appeal)",
		CourtFeeFactor:     4.0,
		FeeBasis:           "GKG",
		RAVGFactor:         1.6,
		RATGFactor:         1.2,
		PAVGFactor:         1.6,
		PATGFactor:         1.2,
		HasPatentAttorneys: true,
	},
	{
		Key:                "BGH_NZB",
		Label:              "BGH (Nichtzulassungsbeschwerde)",
		LabelEN:            "Federal Court of Justice (Leave to Appeal)",
		CourtFeeFactor:     2.0,
		FeeBasis:           "GKG",
		RAVGFactor:         2.3,
		RATGFactor:         1.2,
		PAVGFactor:         1.6,
		PATGFactor:         1.2,
		HasPatentAttorneys: true,
	},
	{
		Key:                "BGH_REV",
		Label:              "BGH (Revision)",
		LabelEN:            "Federal Court of Justice (Revision)",
		CourtFeeFactor:     5.0,
		FeeBasis:           "GKG",
		RAVGFactor:         2.3,
		RATGFactor:         1.5,
		PAVGFactor:         1.6,
		PATGFactor:         1.5,
		HasPatentAttorneys: true,
	},
}

// DENullityInstances lists the court instances for DE patent nullity.
var DENullityInstances = []InstanceMeta{
	{
		Key:                "BPatG",
		Label:              "BPatG (Nichtigkeitsverfahren)",
		LabelEN:            "Federal Patent Court (Nullity)",
		CourtFeeFactor:     4.5,
		FeeBasis:           "PatKostG",
		RAVGFactor:         1.3,
		RATGFactor:         1.2,
		PAVGFactor:         1.3,
		PATGFactor:         1.2,
		HasPatentAttorneys: true,
	},
	{
		Key:                "BGH_NULLITY",
		Label:              "BGH (Nichtigkeitsberufung)",
		LabelEN:            "Federal Court of Justice (Nullity Appeal)",
		CourtFeeFactor:     6.0,
		FeeBasis:           "GKG",
		RAVGFactor:         1.6,
		RATGFactor:         1.5,
		PAVGFactor:         1.6,
		PATGFactor:         1.5,
		HasPatentAttorneys: true,
	},
}

// AllDEInstances returns all DE instance metadata in order.
func AllDEInstances() []InstanceMeta {
	all := make([]InstanceMeta, 0, len(DEInfringementInstances)+len(DENullityInstances))
	all = append(all, DEInfringementInstances...)
	all = append(all, DENullityInstances...)
	return all
}

// UPCFeeSchedules contains UPC court fee data by version.
var UPCFeeSchedules = map[string]UPCFeeSchedule{
	"pre2026": {
		Label:             "UPC (vor 2026)",
		FixedInfringement: 11000,
		FixedRevocation:   20000,
		ValueBased: []UPCFeeBracket{
			{ptr(500000), 0},
			{ptr(750000), 2500},
			{ptr(1000000), 4000},
			{ptr(1500000), 8000},
			{ptr(2000000), 13000},
			{ptr(3000000), 20000},
			{ptr(4000000), 26000},
			{ptr(5000000), 32000},
			{ptr(6000000), 39000},
			{ptr(7000000), 46000},
			{ptr(8000000), 52000},
			{ptr(9000000), 58000},
			{ptr(10000000), 65000},
			{ptr(15000000), 75000},
			{ptr(20000000), 100000},
			{ptr(25000000), 125000},
			{ptr(30000000), 150000},
			{ptr(50000000), 250000},
			{nil, 325000},
		},
		RecoverableCosts: []UPCRecoverableCost{
			{ptr(250000), 38000},
			{ptr(500000), 56000},
			{ptr(1000000), 112000},
			{ptr(2000000), 200000},
			{ptr(4000000), 400000},
			{ptr(8000000), 600000},
			{ptr(16000000), 800000},
			{ptr(30000000), 1200000},
			{ptr(50000000), 1500000},
			{nil, 2000000},
		},
		SMEReduction: 0.4,
	},
	"2026": {
		Label:             "UPC (ab 2026)",
		FixedInfringement: 14600,
		FixedRevocation:   26500,
		ValueBased: []UPCFeeBracket{
			{ptr(500000), 0},
			{ptr(750000), 3300},
			{ptr(1000000), 5300},
			{ptr(1500000), 10600},
			{ptr(2000000), 17200},
			{ptr(3000000), 26400},
			{ptr(4000000), 34300},
			{ptr(5000000), 42200},
			{ptr(6000000), 51500},
			{ptr(7000000), 60700},
			{ptr(8000000), 68600},
			{ptr(9000000), 76600},
			{ptr(10000000), 85800},
			{ptr(15000000), 99000},
			{ptr(20000000), 132000},
			{ptr(25000000), 165000},
			{ptr(30000000), 198000},
			{ptr(50000000), 330000},
			{nil, 429000},
		},
		RecoverableCosts: []UPCRecoverableCost{
			{ptr(250000), 38000},
			{ptr(500000), 56000},
			{ptr(1000000), 112000},
			{ptr(2000000), 200000},
			{ptr(4000000), 400000},
			{ptr(8000000), 600000},
			{ptr(16000000), 800000},
			{ptr(30000000), 1200000},
			{ptr(50000000), 1500000},
			{nil, 2000000},
		},
		SMEReduction: 0.5,
	},
}

// EPAFees contains fixed fees for EPA proceedings.
var EPAFees = map[string]EPAFee{
	"EPA_OPPOSITION": {
		Key:     "EPA_OPPOSITION",
		Label:   "Einspruch",
		LabelEN: "Opposition",
		Fee:     880,
		SMEFee:  880,
	},
	// EPO appeal fee per Rule 6 EPC-Gebühren, version 2024-04-01. Standard fee
	// only; reduced fee for natural persons / SMEs (Rule 7a(2)(a-d)) is 2.015€ —
	// surface that separately if/when m signals.
	"EPA_APPEAL": {
		Key:     "EPA_APPEAL",
		Label:   "Einspruchsbeschwerde",
		LabelEN: "Appeal from Opposition",
		Fee:     2925,
		SMEFee:  2015,
	},
}

func ptr(v float64) *float64 {
	return &v
}
