package bootstrap

// This file is the Go mirror of the DESIRED schema, create order, reconcile
// order and INDEXES in scripts/setup-pocketbase.mjs. Keep the two in sync: edit
// here and re-run the server (bootstrap applies on startup), or run the script.
//
// Access rules are left null on every collection on purpose — every client goes
// through the API Server, which authenticates as a superuser, so the database is
// never exposed directly (including attachments, proxied by the API).

// collectionsSchema is the desired field set per collection.
var collectionsSchema = map[string][]fieldDef{
	"cars": {
		fText("name", true),
		fText("make", false),
		fText("model", false),
		fNumber("year"),
		fText("registration", false),
		fText("registration_country", false),
		fText("vin", false),
		fNumber("service_interval_days"),
		fNumber("service_interval_km"),
		// Roadworthiness inspection cycle. Only prefills a check's next-due date.
		fNumber("technical_check_interval_days"),
		fText("oil_spec", false),
		fText("transmission_oil_spec", false),
		fText("differential_oil_spec", false),
		fText("brake_fluid_spec", false),
		fText("coolant_spec", false),
		fNumber("current_km"),
		// Bi-fuel LPG conversions are their own choice: the car runs on either tank.
		fSelect("fuel_type", []string{
			"petrol", "petrol_lpg", "diesel", "diesel_lpg", "hybrid", "electric", "hydrogen",
		}, false),
		// ISO 8601 reduced precision: "2015", "2015-03" or "2015-03-10". A build
		// date is often only half known; see normalizeBuildDate in api/cars.go.
		fText("build_date", false),
		fText("first_registration_date", false), // ISO YYYY-MM-DD
		// Link to the manufacturer service this car came from: the plugin name plus
		// that plugin's own id for the vehicle (the VIN, for Toyota). See
		// internal/api/vehicleproviders.go. Blank for a hand-entered car.
		fText("provider", false),
		fText("provider_vehicle_id", false),
		// What this car's page shows: the tabs switched off (["fuel"] on an EV)
		// and the Information fields switched off (["differentialOil"] on a car
		// without one). Properties of the car, so everyone it is shared with sees
		// the same page. Stored as the hidden sets, so anything added in a later
		// release is on by default. Keys are validated in internal/api/cars.go.
		fJSON("hidden_tabs", 2000),
		fJSON("hidden_fields", 2000),
		// And the columns of the Service history table (["parts"] for a reader who
		// never records what was changed). Date is not hideable and so never
		// appears here.
		fJSON("hidden_service_columns", 2000),
		// And the parts its services never change (["oil"] on an EV), which come
		// off the service form and out of that column together.
		fJSON("hidden_service_parts", 2000),
		// The order the tabs are laid out in, as tab keys, the same for the
		// Information rows, the Service history columns, and the connected
		// service's headline readings. Empty means the page's own default order.
		fJSON("tab_order", 2000),
		fJSON("field_order", 2000),
		fJSON("service_column_order", 2000),
		fJSON("metric_order", 2000),
		// Owner of this car. Non-cascading: deleting a user must not wipe their cars.
		fRelation("owner", "users", false, false),
	},
	"service_records": {
		fRelation("car", "cars", true, true),
		fDate("date", true),
		fNumber("km"),
		fBool("changed_oil"),
		fBool("changed_engine_air_filter"),
		fBool("changed_cabin_air_filter"),
		fText("notes", false),
		attachment(), // the workshop receipt / stamped service-book page
	},
	// Mandatory roadworthiness inspections (przegląd techniczny / MOT / TÜV).
	"technical_checks": {
		fRelation("car", "cars", true, true),
		fDate("date", true),
		fSelect("result", []string{"passed", "failed"}, false),
		fNumber("cost"),
		fText("station", false),
		fDate("valid_until", false),
		fText("notes", false),
		attachment(), // the certificate
	},
	"parts": {
		fRelation("car", "cars", true, true),
		fText("name", true),
		fText("part_number", false),
		fText("category", false),
		fText("notes", false),
		attachment(), // a photo of the box, or the part's spec sheet
	},
	// Fuel refills. Consumption is derived on read, not stored.
	"fuel_entries": {
		fRelation("car", "cars", true, true),
		fDate("date", true),
		fNumber("km"), // odometer at the pump
		fNumber("liters"),
		fNumber("cost"),
		fBool("full_tank"),
		fBool("missed_fill"),
		fText("station", false),
		fText("notes", false),
		attachment(), // the pump receipt
	},
	// Charging sessions for an electric car — the EV counterpart of fuel_entries,
	// same shape so the two logs behave alike. Consumption is derived on read.
	"charging_sessions": {
		fRelation("car", "cars", true, true),
		fDate("date", true),
		fNumber("km"), // odometer when plugging in
		fNumber("kwh"),
		fNumber("cost"),
		fBool("full_charge"),
		fBool("missed_session"),
		fText("location", false), // "Home", "Ionity Køge"
		fText("notes", false),
		attachment(), // the charge point's receipt
	},
	// Workshop visits and repairs (unplanned/one-off garage work with a labour bill).
	"maintenance_entries": {
		fRelation("car", "cars", true, true),
		fDate("date", true),
		fNumber("km"),
		fSelect("type", []string{"repair", "inspection", "bodywork", "tyres", "diagnostics", "recall", "warranty", "other"}, false),
		fSelect("status", []string{"scheduled", "in_progress", "completed"}, false),
		fText("workshop", false),
		fText("location", false),
		fText("description", false),
		fText("parts_used", false),
		fNumber("labor_cost"),
		fNumber("parts_cost"),
		fText("invoice_number", false),
		fDate("warranty_until", false),
		fText("notes", false),
		attachment(), // the workshop's invoice
	},
	// Insurance, pollution certificates, registration papers … expiry drives reminders.
	"car_documents": {
		fRelation("car", "cars", true, true),
		fSelect("type", []string{"insurance", "pollution", "registration", "inspection", "roadTax", "warranty", "other"}, false),
		fText("title", true),
		fText("provider", false),
		fText("reference", false),
		fDate("issue_date", false),
		fDate("expiry_date", false),
		fNumber("cost"),
		fText("notes", false),
		attachment(), // the scan/PDF of the paperwork
	},
	// User-set reminders (derived document/service ones are computed on read).
	"reminders": {
		fRelation("car", "cars", true, true),
		fText("title", true),
		fSelect("type", []string{"maintenance", "document", "service", "inspection", "other"}, false),
		fDate("due_date", false),
		fNumber("due_km"),
		fNumber("repeat_days"),
		fNumber("repeat_km"),
		fBool("done"),
		fDate("done_at", false),
		fText("notes", false),
	},
	// Per-car sharing grants. Cascades on both relations.
	"car_shares": {
		fRelation("car", "cars", true, true),
		fRelation("user", "users", true, true),
		fSelect("permission", []string{"read", "write"}, true),
		fAutodate("created", true, false),
	},
	// Append-only audit trail for OCPP charger control. Actor/org stored as plain
	// text ids (not relations) so the trail survives user or org deletion.
	"control_audit": {
		fText("user_id", false),
		fText("org_id", false),
		fText("serial", false),
		fText("action", true),
		fText("result", false),
		fJSON("params", 10000),
		fAutodate("created", true, false),
	},
	// Server-wide settings as a single record, keyed "global". Today it holds
	// pluginSettings: the top (L1) layer of the integration cascade — every
	// plugin's enable state, its global config, and the registration of any
	// external HTTP plugin. The org (L2) and user (L3) layers keep their own
	// plugin config in a field of the same name below, so the global layer is
	// stored the way they are instead of in a file beside the binary.
	"app_settings": {
		fText("key", true),
		fJSON("pluginSettings", 200000),
	},
	// Tenants that users belong to.
	"organizations": {
		fText("name", true),
		fAutodate("created", true, false),
		// Per-organization plugin/integration config (middle layer of the cascade).
		fJSON("pluginSettings", 100000),
	},
	// The chargers a user owns — their own wallbox, not the public network. A
	// charger belongs to a person rather than to a car: it charges whichever car
	// is plugged into it, and it outlives any of them.
	"home_chargers": {
		fText("name", true),
		fText("serial", false),
		fText("vendor", false), // "Anker Solix", "Greencell" — who makes it
		fText("model", false),  // "A5191"
		fText("site_name", false),
		fNumber("power_kw"),
		fText("connector", false),
		// Where this charger came from: the charger-provider id plus that
		// provider's own id for it (the serial, for both providers we speak to).
		// Blank for one added by hand. See internal/api/chargerproviders.go.
		fText("provider", false),
		fText("provider_charger_id", false),
		// Owner. Non-cascading, like a car's: deleting a user must not silently
		// wipe the records they own.
		fRelation("owner", "users", false, false),
		// A charger carries no date of its own, so the import order is the only
		// order there is to list them in. PocketBase adds no created field to a
		// collection defined through the API, so it is declared here like the
		// audit trail's.
		fAutodate("created", true, false),
	},
	// Custom fields layered onto the built-in "users" auth collection.
	"users": {
		fText("bio", false),
		fSelect("theme", []string{"light", "dark", "system"}, false),
		fText("locale", false),
		fSelect("date_format", []string{"YMD", "DMY_NUM", "DMY", "MDY"}, false),
		// "auto" is the region's own convention, which is what every clock in the
		// app read before this field existed.
		fSelect("time_format", []string{"auto", "24", "12"}, false),
		fSelect("currency", []string{
			"EUR", "GBP", "CHF", "PLN", "CZK", "HUF", "RON", "BGN", "DKK", "SEK", "NOK",
			"ISK", "ALL", "AMD", "AZN", "BAM", "BYN", "GEL", "MDL", "MKD", "RSD", "RUB",
			"TRY", "UAH", "USD", "CAD", "AUD", "JPY",
		}, false),
		fSelect("font_size", []string{"small", "medium", "large"}, false),
		// Holds every arrangement on this user's pages still — the garage, a
		// car's tabs and Information rows, the provider's readings — so reading a
		// page cannot nudge its layout. Per user, like the garage order.
		fBool("drag_locked"),
		fDate("deletion_requested_at", false),
		// Access role. Empty value is treated as "user" by the API.
		fSelect("role", []string{"user", "admin", "superadmin"}, false),
		// Organization membership. Non-cascading: deleting an org keeps its people.
		fRelation("organization", "organizations", false, false),
		// Per-user plugin/integration config (bottom layer of the cascade).
		fJSON("pluginSettings", 100000),
		// The garage order: car ids in the order this user arranged them. Per
		// user rather than per car, so it also covers cars shared with them and
		// never reorders somebody else's garage.
		fJSON("car_order", 20000),
		// The charging page's tab order. Per user like the garage order, and for
		// the same reason: it is this person's arrangement of their own page.
		fJSON("charger_tab_order", 2000),
		// The charging page's card order, stored the same way as its tab order.
		fJSON("charger_card_order", 2000),
	},
}

// createOrder is the dependency order for creating missing collections.
// "users" is PocketBase's built-in auth collection and is never created here.
var createOrder = []string{
	"app_settings",
	"organizations",
	"cars",
	"service_records",
	"technical_checks",
	"parts",
	"car_shares",
	"fuel_entries",
	"charging_sessions",
	"maintenance_entries",
	"car_documents",
	"reminders",
	"control_audit",
	"home_chargers",
}

// reconcileOrder additionally includes "users" so its custom fields (role,
// organization, preferences) are added to the built-in collection.
var reconcileOrder = []string{
	"app_settings",
	"organizations",
	"users",
	"cars",
	"service_records",
	"technical_checks",
	"parts",
	"car_shares",
	"fuel_entries",
	"charging_sessions",
	"maintenance_entries",
	"car_documents",
	"reminders",
	"control_audit",
	"home_chargers",
}

// indexes are extra SQL indexes applied at collection-create time.
var indexes = map[string][]string{
	// One settings record per key, so the global singleton cannot be duplicated.
	"app_settings":        {"CREATE UNIQUE INDEX `idx_app_settings_key` ON `app_settings` (`key`)"},
	"organizations":       {"CREATE UNIQUE INDEX `idx_organizations_name` ON `organizations` (`name`)"},
	"fuel_entries":        {"CREATE INDEX `idx_fuel_entries_car_km` ON `fuel_entries` (`car`, `km`)"},
	"charging_sessions":   {"CREATE INDEX `idx_charging_sessions_car_km` ON `charging_sessions` (`car`, `km`)"},
	"maintenance_entries": {"CREATE INDEX `idx_maintenance_entries_car_date` ON `maintenance_entries` (`car`, `date`)"},
	"car_documents":       {"CREATE INDEX `idx_car_documents_car_expiry` ON `car_documents` (`car`, `expiry_date`)"},
	"reminders":           {"CREATE INDEX `idx_reminders_car_due` ON `reminders` (`car`, `due_date`)"},
	"technical_checks":    {"CREATE INDEX `idx_technical_checks_car_date` ON `technical_checks` (`car`, `date`)"},
	// A charger is looked up by its owner, and by serial when checking whether
	// the account it came from has already been imported.
	"home_chargers": {"CREATE INDEX `idx_home_chargers_owner_serial` ON `home_chargers` (`owner`, `serial`)"},
	"control_audit": {
		"CREATE INDEX `idx_control_audit_serial_created` ON `control_audit` (`serial`, `created`)",
		"CREATE INDEX `idx_control_audit_user_created` ON `control_audit` (`user_id`, `created`)",
	},
}
