// Package models defines the Extrudex domain model structs.
// These map 1:1 to PostgreSQL tables with snake_case JSON serialization.
// Nullable fields use pointer types; all timestamps are time.Time.
package models

import "time"

// ============================================================================
// Lookup Tables
// ============================================================================

// PrinterType represents a printer technology category (fdm, resin, etc.).
type PrinterType struct {
	ID        int       `json:"id"`
	Name      string    `json:"name"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

// JobStatus represents a print job lifecycle state.
type JobStatus struct {
	ID        int       `json:"id"`
	Name      string    `json:"name"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

// MaterialBase represents a base material type (PLA, PETG, ABS, etc.).
// Density and temperature ranges are stored here for grams-calculation and slicing guidance.
type MaterialBase struct {
	ID               int        `json:"id"`
	Name             string     `json:"name"`
	DensityGCm3      float64    `json:"density_g_cm3"`
	ExtrusionTempMin *int       `json:"extrusion_temp_min,omitempty"`
	ExtrusionTempMax *int       `json:"extrusion_temp_max,omitempty"`
	BedTempMin       *int       `json:"bed_temp_min,omitempty"`
	BedTempMax       *int       `json:"bed_temp_max,omitempty"`
	CreatedAt        time.Time  `json:"created_at"`
	UpdatedAt        time.Time  `json:"updated_at"`
}

// MaterialFinish represents the visual/texture finish (Basic, Silk, Matte, etc.).
type MaterialFinish struct {
	ID          int       `json:"id"`
	Name        string    `json:"name"`
	Description *string   `json:"description,omitempty"`
	CreatedAt   time.Time `json:"created_at"`
	UpdatedAt   time.Time `json:"updated_at"`
}

// MaterialModifier represents an additive property (Carbon Fiber, Wood-Filled, etc.).
type MaterialModifier struct {
	ID          int       `json:"id"`
	Name        string    `json:"name"`
	Description *string   `json:"description,omitempty"`
	CreatedAt   time.Time `json:"created_at"`
	UpdatedAt   time.Time `json:"updated_at"`
}

// ============================================================================
// Core Entity Tables
// ============================================================================

// Printer represents a 3D printer in the fleet.
type Printer struct {
	ID              int        `json:"id"`
	Name            string     `json:"name"`
	PrinterTypeID   int        `json:"printer_type_id"`
	PrinterType     *PrinterType `json:"printer_type,omitempty"` // populated on JOIN queries
	Manufacturer    *string    `json:"manufacturer,omitempty"`
	Model           *string    `json:"model,omitempty"`
	MoonrakerURL    *string    `json:"moonraker_url,omitempty"`
	MoonrakerAPIKey *string    `json:"moonraker_api_key,omitempty"`
	MQTTBrokerHost  *string    `json:"mqtt_broker_host,omitempty"`
	MQTTTopicPrefix *string    `json:"mqtt_topic_prefix,omitempty"`
	MQTTTLSEnabled  bool       `json:"mqtt_tls_enabled"`
	IsActive        bool       `json:"is_active"`
	CreatedAt       time.Time  `json:"created_at"`
	UpdatedAt       time.Time  `json:"updated_at"`
}

// FilamentSpool represents a physical filament spool in inventory.
// material_finish_id defaults to 1 ("Basic"); material_modifier_id is optional.
// Grams are always physically measured values — grams_used is derived, not stored.
type FilamentSpool struct {
	ID                    int             `json:"id"`
	Name                  string          `json:"name"`
	MaterialBaseID        int             `json:"material_base_id"`
	MaterialBase          *MaterialBase   `json:"material_base,omitempty"`   // JOIN
	MaterialFinishID      int             `json:"material_finish_id"`
	MaterialFinish        *MaterialFinish `json:"material_finish,omitempty"` // JOIN
	MaterialModifierID    *int            `json:"material_modifier_id,omitempty"`
	MaterialModifier      *MaterialModifier `json:"material_modifier,omitempty"` // JOIN
	ColorHex              string          `json:"color_hex"`
	Brand                 *string         `json:"brand,omitempty"`
	DiameterMM            float64         `json:"diameter_mm"`
	InitialGrams          int             `json:"initial_grams"`
	RemainingGrams        int             `json:"remaining_grams"`
	SpoolWeightGrams      *int            `json:"spool_weight_grams,omitempty"`
	CostUSD               *float64        `json:"cost_usd,omitempty"`
	LowStockThresholdGrams int            `json:"low_stock_threshold_grams"`
	Notes                 *string         `json:"notes,omitempty"`
	Barcode               *string         `json:"barcode,omitempty"`
	DeletedAt             *time.Time      `json:"deleted_at,omitempty"`
	CreatedAt             time.Time       `json:"created_at"`
	UpdatedAt             time.Time       `json:"updated_at"`
}

// PrintJob represents a single print on a specific printer.
// The filament_spool_id is a convenience reference; multi-spool jobs track usage in usage_logs.
type PrintJob struct {
	ID                      int         `json:"id"`
	PrinterID               int         `json:"printer_id"`
	Printer                 *Printer    `json:"printer,omitempty"`      // JOIN
	FilamentSpoolID         *int        `json:"filament_spool_id,omitempty"`
	FilamentSpool           *FilamentSpool `json:"filament_spool,omitempty"` // JOIN
	JobName                 string      `json:"job_name"`
	FileName                *string     `json:"file_name,omitempty"`
	JobStatusID             int         `json:"job_status_id"`
	JobStatus               *JobStatus  `json:"job_status,omitempty"`  // JOIN
	StartedAt               *time.Time  `json:"started_at,omitempty"`
	CompletedAt             *time.Time  `json:"completed_at,omitempty"`
	DurationSeconds         *int        `json:"duration_seconds,omitempty"`
	EstimatedDurationSeconds *int       `json:"estimated_duration_seconds,omitempty"`
	TotalMMExtruded         *float64    `json:"total_mm_extruded,omitempty"`
	TotalGramsUsed          *float64    `json:"total_grams_used,omitempty"`
	TotalCostUSD            *float64    `json:"total_cost_usd,omitempty"`
	Notes                   *string     `json:"notes,omitempty"`
	DeletedAt               *time.Time  `json:"deleted_at,omitempty"`
	CreatedAt               time.Time   `json:"created_at"`
	UpdatedAt               time.Time   `json:"updated_at"`
}

// UsageLog records filament consumption for a specific spool during a print job.
// This is the atomic unit of filament tracking — grams are derived from mm_extruded.
type UsageLog struct {
	ID              int            `json:"id"`
	PrintJobID      int            `json:"print_job_id"`
	PrintJob        *PrintJob      `json:"print_job,omitempty"`        // JOIN
	FilamentSpoolID int            `json:"filament_spool_id"`
	FilamentSpool   *FilamentSpool `json:"filament_spool,omitempty"`   // JOIN
	MMExtruded      float64        `json:"mm_extruded"`
	GramsUsed       float64        `json:"grams_used"`
	CostUSD         *float64       `json:"cost_usd,omitempty"`
	LoggedAt        time.Time      `json:"logged_at"`
	CreatedAt       time.Time      `json:"created_at"`
}

// ============================================================================
// Application Settings
// ============================================================================

// Setting represents a key-value application configuration entry.
// The value is stored as JSONB in PostgreSQL, allowing flexible typed config.
type Setting struct {
	ID          int       `json:"id"`
	Key         string    `json:"key"`
	Value       []byte    `json:"value"`  // raw JSON — marshalled/unmarshalled by caller
	Description *string   `json:"description,omitempty"`
	CreatedAt   time.Time `json:"created_at"`
	UpdatedAt   time.Time `json:"updated_at"`
}
