package services

// Variable resolvers — the paliad-side implementations of
// docforge.VariableResolver (t-paliad-349 slice 3). Each wraps one of the
// addXxxVars push-builders, capturing the entity it needs, so the proven
// builder bodies stay byte-for-byte unchanged while the composition moves
// behind the docforge.ResolverSet seam. SubmissionVarsService.Build wires
// the applicable resolvers and calls ResolverSet.BuildBag().
//
// These live in paliad (not docforge) because they read paliad's domain
// model — branding, user, project, parties, deadline_rules, deadlines. A
// second docforge consumer implements its own resolvers against its own
// data and plugs them into a ResolverSet the same way.

import (
	"time"

	"mgit.msbls.de/m/paliad/internal/models"
	"mgit.msbls.de/m/paliad/pkg/docforge"
)

// Compile-time conformance: each resolver satisfies docforge.VariableResolver.
var (
	_ docforge.VariableResolver = firmResolver{}
	_ docforge.VariableResolver = todayResolver{}
	_ docforge.VariableResolver = userResolver{}
	_ docforge.VariableResolver = proceduralEventResolver{}
	_ docforge.VariableResolver = projectResolver{}
	_ docforge.VariableResolver = partiesResolver{}
	_ docforge.VariableResolver = deadlineResolver{}
)

// vk is a terse constructor for a catalogue entry in the given group.
func vk(group, key, de, en string) docforge.VariableKey {
	return docforge.VariableKey{Key: key, LabelDE: de, LabelEN: en, Group: group}
}

// SubmissionVariableCatalogue returns the full variable catalogue for the
// submission resolvers — every (key, DE/EN label, namespace) the sidebar
// form and the authoring palette can offer. Built from the resolvers'
// Keys() with no entity state, so it needs no DB call. This is the single
// source of truth for variable labels, replacing the duplicated TS
// VARIABLE_LABELS table (t-paliad-349 slice 5).
func SubmissionVariableCatalogue() []docforge.VariableKey {
	return docforge.NewResolverSet(
		firmResolver{},
		todayResolver{},
		userResolver{},
		proceduralEventResolver{},
		projectResolver{},
		partiesResolver{},
		deadlineResolver{},
	).Catalogue()
}

// firmResolver populates firm.* from process-wide branding.
type firmResolver struct{}

func (firmResolver) Namespace() string           { return "firm" }
func (firmResolver) Populate(bag PlaceholderMap) { addFirmVars(bag) }
func (firmResolver) Keys() []docforge.VariableKey {
	return []docforge.VariableKey{
		vk("firm", "firm.name", "Kanzlei", "Firm"),
		vk("firm", "firm.signature_block", "Signatur-Block", "Signature block"),
	}
}

// todayResolver populates today.* from the build-time clock.
type todayResolver struct{ now time.Time }

func (todayResolver) Namespace() string             { return "today" }
func (r todayResolver) Populate(bag PlaceholderMap) { addTodayVars(bag, r.now) }
func (todayResolver) Keys() []docforge.VariableKey {
	return []docforge.VariableKey{
		vk("today", "today", "Heute", "Today"),
		vk("today", "today.iso", "Heute (ISO)", "Today (ISO)"),
		vk("today", "today.long_de", "Heute (DE lang)", "Today (DE long)"),
		vk("today", "today.long_en", "Heute (EN lang)", "Today (EN long)"),
	}
}

// userResolver populates user.* from the caller's row.
type userResolver struct{ user *models.User }

func (userResolver) Namespace() string             { return "user" }
func (r userResolver) Populate(bag PlaceholderMap) { addUserVars(bag, r.user) }
func (userResolver) Keys() []docforge.VariableKey {
	return []docforge.VariableKey{
		vk("user", "user.display_name", "Bearbeiter", "Author"),
		vk("user", "user.email", "E-Mail", "Email"),
		vk("user", "user.office", "Büro", "Office"),
	}
}

// proceduralEventResolver populates procedural_event.* and the legacy
// rule.* alias from the published deadline_rule.
type proceduralEventResolver struct {
	rule *models.DeadlineRule
	lang string
}

func (proceduralEventResolver) Namespace() string             { return "procedural_event" }
func (r proceduralEventResolver) Populate(bag PlaceholderMap) { addRuleVars(bag, r.rule, r.lang) }
func (proceduralEventResolver) Keys() []docforge.VariableKey {
	return []docforge.VariableKey{
		vk("procedural_event", "procedural_event.code", "Code (Verfahrensschritt)", "Code (procedural event)"),
		vk("procedural_event", "procedural_event.name", "Verfahrensschritt", "Procedural event"),
		vk("procedural_event", "procedural_event.name_de", "Verfahrensschritt (DE)", "Procedural event (DE)"),
		vk("procedural_event", "procedural_event.name_en", "Verfahrensschritt (EN)", "Procedural event (EN)"),
		vk("procedural_event", "procedural_event.legal_source", "Rechtsgrundlage (Code)", "Legal source (code)"),
		vk("procedural_event", "procedural_event.legal_source_pretty", "Rechtsgrundlage", "Legal source"),
		vk("procedural_event", "procedural_event.primary_party", "Partei (typisch)", "Primary party"),
		vk("procedural_event", "procedural_event.event_kind", "Art des Verfahrensschritts", "Procedural-event kind"),
		// Legacy rule.* aliases — @deprecated, kept forever (m/paliad#93 Q7).
		vk("procedural_event", "rule.submission_code", "Schriftsatz-Code (legacy)", "Submission code (legacy)"),
		vk("procedural_event", "rule.name", "Schriftsatz (legacy)", "Submission (legacy)"),
		vk("procedural_event", "rule.name_de", "Schriftsatz (DE, legacy)", "Submission (DE, legacy)"),
		vk("procedural_event", "rule.name_en", "Schriftsatz (EN, legacy)", "Submission (EN, legacy)"),
		vk("procedural_event", "rule.legal_source", "Rechtsgrundlage (Code, legacy)", "Legal source (code, legacy)"),
		vk("procedural_event", "rule.legal_source_pretty", "Rechtsgrundlage (legacy)", "Legal source (legacy)"),
		vk("procedural_event", "rule.primary_party", "Partei (typisch, legacy)", "Primary party (legacy)"),
		vk("procedural_event", "rule.event_type", "Schriftsatz-Typ (legacy)", "Event type (legacy)"),
	}
}

// projectResolver populates project.* from the project + its proceeding type.
type projectResolver struct {
	project *models.Project
	pt      *models.ProceedingType
	lang    string
}

func (projectResolver) Namespace() string             { return "project" }
func (r projectResolver) Populate(bag PlaceholderMap) { addProjectVars(bag, r.project, r.pt, r.lang) }
func (projectResolver) Keys() []docforge.VariableKey {
	return []docforge.VariableKey{
		vk("project", "project.title", "Projekttitel", "Project title"),
		vk("project", "project.reference", "Aktenzeichen (intern)", "Internal reference"),
		vk("project", "project.case_number", "Aktenzeichen (Gericht)", "Court case number"),
		vk("project", "project.court", "Gericht", "Court"),
		vk("project", "project.patent_number", "Patentnummer", "Patent number"),
		vk("project", "project.patent_number_upc", "Patentnummer (UPC-Format)", "Patent number (UPC format)"),
		vk("project", "project.filing_date", "Anmeldedatum", "Filing date"),
		vk("project", "project.grant_date", "Erteilungsdatum", "Grant date"),
		vk("project", "project.our_side", "Unsere Seite", "Our side"),
		vk("project", "project.our_side_de", "Unsere Seite (DE)", "Our side (DE)"),
		vk("project", "project.our_side_en", "Unsere Seite (EN)", "Our side (EN)"),
		vk("project", "project.instance_level", "Instanz", "Instance"),
		vk("project", "project.client_number", "Mandantennummer", "Client number"),
		vk("project", "project.matter_number", "Matter-Nummer", "Matter number"),
		vk("project", "project.proceeding.code", "Verfahrenstyp (Code)", "Proceeding type (code)"),
		vk("project", "project.proceeding.name", "Verfahrenstyp", "Proceeding type"),
		vk("project", "project.proceeding.name_de", "Verfahrenstyp (DE)", "Proceeding type (DE)"),
		vk("project", "project.proceeding.name_en", "Verfahrenstyp (EN)", "Proceeding type (EN)"),
	}
}

// partiesResolver populates parties.* from the (already filtered) party list.
type partiesResolver struct{ parties []models.Party }

func (partiesResolver) Namespace() string             { return "parties" }
func (r partiesResolver) Populate(bag PlaceholderMap) { addPartyVars(bag, r.parties) }

// Keys returns the flat, user-facing party forms (the power-user override
// rows the sidebar shows). The indexed (parties.claimant.0.name) and
// joined (parties.claimants) forms Populate also emits are not catalogue
// entries — they're resolved into the bag but not offered in the palette.
func (partiesResolver) Keys() []docforge.VariableKey {
	return []docforge.VariableKey{
		vk("parties", "parties.claimant.name", "Klägerin", "Claimant"),
		vk("parties", "parties.claimant.representative", "Klägerin-Vertreter", "Claimant representative"),
		vk("parties", "parties.defendant.name", "Beklagte", "Defendant"),
		vk("parties", "parties.defendant.representative", "Beklagten-Vertreter", "Defendant representative"),
		vk("parties", "parties.other.name", "Weitere Partei", "Other party"),
		vk("parties", "parties.other.representative", "Weitere-Partei-Vertreter", "Other party representative"),
	}
}

// deadlineResolver populates deadline.* from the next pending deadline.
type deadlineResolver struct {
	deadline *models.Deadline
	project  *models.Project
	lang     string
}

func (deadlineResolver) Namespace() string { return "deadline" }
func (r deadlineResolver) Populate(bag PlaceholderMap) {
	addDeadlineVars(bag, r.deadline, r.project, r.lang)
}
func (deadlineResolver) Keys() []docforge.VariableKey {
	return []docforge.VariableKey{
		vk("deadline", "deadline.due_date", "Frist (ISO)", "Deadline (ISO)"),
		vk("deadline", "deadline.due_date_long_de", "Frist (DE lang)", "Deadline (DE long)"),
		vk("deadline", "deadline.due_date_long_en", "Frist (EN lang)", "Deadline (EN long)"),
		vk("deadline", "deadline.original_due_date", "Ursprüngliche Frist", "Original deadline"),
		vk("deadline", "deadline.computed_from", "Frist berechnet aus", "Deadline computed from"),
		vk("deadline", "deadline.title", "Frist-Titel", "Deadline title"),
		vk("deadline", "deadline.source", "Frist-Quelle", "Deadline source"),
	}
}
