package plugin

import (
	"fmt"
	"math/rand/v2"
	"strings"
)

// ── St. Guildmore's Memorial Hospital — Nurse Joy Flavor Text ──────────────

// nurseJoyFirstVisit is shown once on the player's first hospital visit.
var nurseJoyFirstVisit = "🏥 **Welcome to St. Guildmore's Memorial Hospital!**\n\n" +
	"We're the official healthcare provider for members of the Adventurer's Guild. " +
	"Even better, we've modeled our pricing after the United States of America, " +
	"which means we offer only the quickest and best care. _whispers_ ...for those who can afford it.\n\n" +
	"Your Guild insurance is on file. Nurse Joy will be right with you.\n\n"

var nurseJoyAdmission = []string{
	"_looks up from clipboard with a bright smile_ Hi! Name? Guild card? Oh you're covered under the Collective, that's wonderful! Let me get Nurse Joy to come take a look at you. _is Nurse Joy_",
	"Oh you're with the Guild? That's great, we love Guild members! Very comprehensive plan. Someone will be right with you! _gestures at chairs_ Can I get you anything while you wait? We have water. It's complimentary. The water is complimentary.",
	"_already typing, still cheerful_ Cause of death? Temporary obviously, just for the record! And your Guild card number? Perfect! We'll get you all sorted out. _sorted out does not mean quickly but she means it warmly_",
	"Welcome to St. Guildmore's! You're in such good hands here. _has said this ten thousand times and means it every single time_ Insurance on file? Wonderful. Take a number and we'll be right with you!",
	"_looks up, immediately sympathetic in a clinical way_ Oh you don't look great! That's okay, that's what we're here for. Guild member? Amazing. Nurse Joy will be right out. _is Nurse Joy. will be right out._",
}

var nurseJoyBillDelivery = []string{
	"_slides it across with a smile_ So that's the total before insurance! Your plan is really good though -- the Collective is wonderful. We're going to call them right now. _already reaching for the phone, still smiling_",
	"Here's the full rate! _sets it down cheerfully_ Don't worry about that number, insurance is going to take care of so much of it. So much. Give us just a sec! _hums while dialing_",
	"That's what we call the pre-insurance figure! It's a big number but honestly that's just how we price things here. The Collective will bring it way down. Way down. _wanders off still visibly pleased with how this is going_",
	"_hands it over like she's giving you a gift_ Your Guild plan is really comprehensive -- one of the better ones we see honestly. Let me just get them on the line! _does not register your expression at all_",
}

// nurseJoyAfterInsurance — format with afterInsurance cost.
// The last entry has two %d placeholders (intentional — she says the number twice).
var nurseJoyAfterInsurance = []string{
	"_practically skips back in_ Great news! The Collective was amazing -- they covered so much of it. Your portion is only **€%d**! _says \"only\" like she's reporting a minor inconvenience_",
	"_beaming_ Okay so the insurance came through and honestly? Really good result today. You're looking at **€%d** out of pocket! That's after everything they covered. _genuinely proud of this outcome_",
	"_sits across from you, clasps hands_ I have such good news. The Collective took care of the bulk of it. Your share is just **€%d**! I know it sounds like a lot but you should see what it was before. _you have seen what it was before_ Actually you did see it. But still -- this is so much better!",
	"_slides over a new, smaller, still alarming piece of paper_ So they covered everything above your threshold! You just owe **€%d**. _taps it encouragingly_ And then you're all set! Good as new! _has never once considered that **€%d** might be a problem_",
}

var nurseJoyCantAfford = []string{
	"Oh! It looks like your balance isn't quite there today! _signals to the orderlies_ That's okay! We'll get you back to where we found you and you can rest up overnight! _waves as the stretcher is wheeled back out_",
	"Hmm! So the balance isn't quite covering it! No worries at all -- _already nodding to someone behind you_ -- the natural recovery process works just as well! We'll get you back to your ditch! Have a great night!",
	"Oh that's a little short! That's okay! _cheerfully_ We're going to pop you back where you were and you'll be right as rain tomorrow morning! _you are deposited back in the ditch_",
}

var nurseJoyNudge = []string{
	"Hi! This is Nurse Joy at St. Guildmore's Memorial! We noticed you haven't come in yet.\n\n" +
		"We have a bed ready and your insurance is all on file! We even have Derek standing by but that's only relevant if there's a billing issue and I'm sure there won't be!\n\n" +
		"Come in whenever you're ready! We're open! _we are always open_\n\n" +
		"Type `!hospital` to check in.",
}

// nurseJoyHaggleFlavor — Nurse Joy's reaction to the player's CHA haggle roll.
// Indexed by hospitalHaggleOutcome (haggleFumble=0, haggleFail=1, haggleWin=2, haggleCrit=3).
var nurseJoyHaggleFlavor = [][]string{
	// haggleFumble — nat 1
	{
		"_you have drooled on the clipboard_ Oh sweetie. _gently dabs at it_ That's okay! We see this all the time. _has not seen this all the time._ Full price, but on the house emotionally!",
		"You opened your mouth and a single, low groan came out. _she nods supportively_ I'll take that as 'fine with the full bill!' Wonderful negotiating!",
		"_you tried to wink and both eyes closed_ Bless. We'll just go with the standard rate, sugar. Don't strain yourself.",
		"You attempted charm. You produced a wet, rattling exhale. _Nurse Joy beams._ \"That's a yes to the full price! Great chat!\"",
		"_you mumbled what you thought was a compliment about her hair_ That was a tube. That was the oxygen tube, honey. Full price!",
	},
	// haggleFail — d20+CHA below DC
	{
		"_smiles, doesn't blink_ I hear you, I do, but our pricing is set by the regional billing council and they are not sentimental people. Full bill it is!",
		"That was a nice try! Really. _pats your hand_ Unfortunately I don't actually have the authority to discount anything, but it's so cute that you asked!",
		"_tilts head sympathetically_ Oh, I would if I could! I really would. _she would not_ Standard rate, sugar.",
		"Mm, no, that one didn't quite land for me. _still smiling_ But you're so brave for trying! Standard pricing applies.",
	},
	// haggleWin — pass
	{
		"_leans in conspiratorially_ You know what? You've been so polite. _types something_ I'm going to push this through as a 'goodwill adjustment.' Half off! Don't tell Derek.",
		"_genuinely charmed_ Oh you're sweet. Okay, okay, I can flag this as a hardship case. Fifty percent off! _winks, has never winked at anyone before_",
		"You know, the system has this little box for 'compassionate review' and I'm just _click_ going to go ahead and check that. There. Half price! Our little secret.",
		"_giggles_ You're trouble. Okay — half off, but only because I like you, and because Derek is on lunch.",
	},
	// haggleCrit — nat 20
	{
		"_completely disarmed_ Oh my god. _puts down clipboard_ I haven't laughed like that on shift in YEARS. You know what? This one's on the house. Derek is going to have a complete meltdown and I do not care.",
		"_dabs at her eye, recovering_ Sir. Ma'am. Whatever-you-are. That was the single most charming thing a corpse has ever said to me. Bill: waived. Walk it off.",
		"_actually blushing_ I — okay. Okay! You know what? Free. It's free. _whispers to the ceiling_ Sorry Derek.",
		"_stares at you for a long moment_ I'm calling it a clinical trial. You're the trial. There is no charge. Get out of here before I change my mind. _winks for real this time_",
		"_to the orderlies_ Tear up the bill. _to you_ You, sugar, are a treasure. Discharge papers, no charge, complimentary water for the road.",
	},
}

var nurseJoyAlive = []string{
	"_looks up from clipboard_ You don't appear to be dead! That's great news! We love when people aren't dead. Come back if that changes! _cheerfully_",
	"_tilts head_ Our records show you're... alive? That's wonderful! We don't actually treat alive people here. It's a whole different department. _waves vaguely_",
}

var nurseJoyAlreadyRevived = "You seem to have recovered on your own! " +
	"That's the body's natural healing process at work. Beautiful thing. " +
	"No charge! _beams_"

// ── Room Announcements ───────────────────────────────────────────────────��─

// hospitalDischargeBillDescriptors are the variants used for the
// "The bill has been described as ..." sentence in the discharge announcement.
// Some are bare adjectives ("devastating"); others are full quoted phrases.
var hospitalDischargeBillDescriptors = []string{
	"\"inhumane but probably normal by USA standards.\"",
	"devastating.",
	"ruinous.",
	"soul-crushing.",
	"\"proof that someone, somewhere, hates me specifically.\"",
	"\"tearing to shreds what little hope I had left for humanity.\"",
	"\"what I imagine my greatest enemies would charge me.\"",
	"\"enough to make me reconsider the whole 'surviving' part.\"",
}

var hospitalDischargeAnnouncePrefix = "🏥 %s has been discharged from St. Guildmore's Memorial Hospital. " +
	"Recovered. Back in action. The bill has been described as %s"

var hospitalDitchAnnounce = "🏥 %s was brought into St. Guildmore's on a stretcher. " +
	"They have been returned to the ditch. They'll be fine tomorrow."

// ── Itemized Bill Generation ───────────────────────────────────────────────

type hospitalBillItem struct {
	Name string
	Note string  // optional italicized sub-line
	Min  float64 // min fraction of total
	Max  float64 // max fraction of total
}

// hospitalBillPool is the pool of possible line items. Each bill picks 8-12.
var hospitalBillPool = []hospitalBillItem{
	{"Resuscitation services (standard)", "", 0.04, 0.10},
	{"Resuscitation services (premium)", "(performed simultaneously with standard, non-optional)", 0.03, 0.08},
	{"Facility fee", "", 0.02, 0.05},
	{"Facility fee (after hours)", "(you died at 2pm. this is contested. we will not contest it.)", 0.02, 0.04},
	{"Physician consultation", "", 0.03, 0.06},
	{"Physician consultation (second opinion)", "(same physician. different hat.)", 0.03, 0.06},
	{"Gauze", "", 0.01, 0.02},
	{"Gauze (application fee)", "", 0.01, 0.02},
	{"Gauze (removal, future, pre-billed)", "", 0.01, 0.03},
	{"Convenience fee", "(thank you for allowing us to exist)", 0.02, 0.05},
	{"Inconvenience fee", "(deterrent to prevent emergency room abuse or usage in general)", 0.02, 0.05},
	{"Guild membership verification fee", "(your guild card was checked. this takes resources.)", 0.01, 0.03},
	{"Administrative processing", "", 0.01, 0.03},
	{"Spiritual realignment surcharge", "(your soul was briefly elsewhere. retrieval is billable.)", 0.02, 0.04},
	{"Bed occupancy charge", "(per minute, retroactive to estimated time of death)", 0.02, 0.05},
	{"Oxygen (ambient)", "(you breathed hospital air. the air is not free.)", 0.01, 0.03},
	{"Emotional support services", "(Nurse Joy smiled at you. that's a service.)", 0.01, 0.02},
	{"Post-mortem orientation fee", "(the pamphlet you did not read.)", 0.01, 0.02},
	{"Equipment sterilization", "(your gear was near our equipment. proximity counts.)", 0.01, 0.03},
	{"Discharge planning", "(we are already planning your discharge. this costs money.)", 0.01, 0.03},
}

// hospitalHolidaySurcharge is included only on holidays.
var hospitalHolidaySurcharge = hospitalBillItem{
	"Holiday surcharge", "(applied if death occurs on or adjacent to a recognized holiday)", 0.02, 0.02,
}

// hospitalFrequentCustomer is included when hospitalVisits > 0.
// It's a "discount" that is actually a positive charge. Because healthcare.
var hospitalFrequentCustomer = hospitalBillItem{
	"Frequent customer discount", "(thank you for your continued patronage.)", 0.01, 0.02,
}

// generateItemizedBill builds a procedural hospital bill that sums to the given total.
func generateItemizedBill(total int64, afterInsurance int64, hospitalVisits int, isHoliday bool) string {
	// Shuffle and pick 8-12 items from the pool
	pool := make([]hospitalBillItem, len(hospitalBillPool))
	copy(pool, hospitalBillPool)
	rand.Shuffle(len(pool), func(i, j int) { pool[i], pool[j] = pool[j], pool[i] })

	count := 8 + rand.IntN(5) // 8-12
	if count > len(pool) {
		count = len(pool)
	}
	items := pool[:count]

	// Add conditional items
	if isHoliday {
		items = append(items, hospitalHolidaySurcharge)
	}
	if hospitalVisits > 0 {
		items = append(items, hospitalFrequentCustomer)
	}

	// Assign amounts
	type billLine struct {
		Name   string
		Note   string
		Amount int64
	}

	var lines []billLine
	var assigned int64

	for _, item := range items {
		frac := item.Min + rand.Float64()*(item.Max-item.Min)
		amount := int64(float64(total) * frac)
		if amount < 1 {
			amount = 1
		}
		lines = append(lines, billLine{Name: item.Name, Note: item.Note, Amount: amount})
		assigned += amount
	}

	// Miscellaneous absorbs the remainder
	misc := total - assigned
	if misc < 0 {
		// Over-assigned — scale everything down proportionally
		scale := float64(total) / float64(assigned)
		assigned = 0
		for i := range lines {
			lines[i].Amount = int64(float64(lines[i].Amount) * scale)
			if lines[i].Amount < 1 {
				lines[i].Amount = 1
			}
			assigned += lines[i].Amount
		}
		misc = total - assigned
	}
	if misc > 0 {
		lines = append(lines, billLine{
			Name:   "Miscellaneous",
			Note:   "",
			Amount: misc,
		})
	}

	// Find max name width for alignment
	maxName := 0
	for _, l := range lines {
		if len(l.Name) > maxName {
			maxName = len(l.Name)
		}
	}
	if maxName < 35 {
		maxName = 35
	}

	// Format
	var sb strings.Builder
	sb.WriteString("```\n")
	sb.WriteString("ST. GUILDMORE'S MEMORIAL HOSPITAL\n")
	sb.WriteString("─────────────────────────────────\n")

	for _, l := range lines {
		padding := maxName - len(l.Name) + 2
		if padding < 2 {
			padding = 2
		}
		sb.WriteString(l.Name)
		sb.WriteString(strings.Repeat(" ", padding))
		sb.WriteString(formatBillAmount(l.Amount))
		sb.WriteByte('\n')
		if l.Note != "" {
			sb.WriteString("    " + l.Note + "\n")
		}
	}

	sb.WriteString("─────────────────────────────────\n")
	totalLabel := "TOTAL (before insurance)"
	padding := maxName - len(totalLabel) + 2
	if padding < 2 {
		padding = 2
	}
	sb.WriteString(totalLabel)
	sb.WriteString(strings.Repeat(" ", padding))
	sb.WriteString(formatBillAmount(total))
	sb.WriteByte('\n')

	insLabel := "Guild Adventurer's Insurance"
	insPadding := maxName - len(insLabel) + 2
	if insPadding < 2 {
		insPadding = 2
	}
	sb.WriteString(insLabel)
	sb.WriteString(strings.Repeat(" ", insPadding))
	sb.WriteString("-" + formatBillAmount(total-afterInsurance))
	sb.WriteByte('\n')

	sb.WriteString("─────────────────────────────────\n")
	oweLabel := "AMOUNT DUE"
	owePadding := maxName - len(oweLabel) + 2
	if owePadding < 2 {
		owePadding = 2
	}
	sb.WriteString(oweLabel)
	sb.WriteString(strings.Repeat(" ", owePadding))
	sb.WriteString(formatBillAmount(afterInsurance))
	sb.WriteByte('\n')
	sb.WriteString("```")

	return sb.String()
}

// formatBillAmount formats an int64 as €X,XXX with comma separators.
func formatBillAmount(n int64) string {
	if n == 0 {
		return "€0"
	}
	neg := n < 0
	if neg {
		n = -n
	}

	// Format with commas
	s := fmt.Sprintf("%d", n)
	if len(s) <= 3 {
		if neg {
			return "-€" + s
		}
		return "€" + s
	}

	// Insert commas from right
	var result strings.Builder
	remainder := len(s) % 3
	if remainder > 0 {
		result.WriteString(s[:remainder])
	}
	for i := remainder; i < len(s); i += 3 {
		if result.Len() > 0 {
			result.WriteByte(',')
		}
		result.WriteString(s[i : i+3])
	}

	if neg {
		return "-€" + result.String()
	}
	return "€" + result.String()
}
