package store import ( "context" "fmt" "strings" "time" "git.warky.dev/wdevs/amcs/internal/generatedmodels" ext "git.warky.dev/wdevs/amcs/internal/types" ) func (db *DB) AddMaintenanceTask(ctx context.Context, t ext.MaintenanceTask) (ext.MaintenanceTask, error) { row := db.pool.QueryRow(ctx, ` insert into maintenance_tasks (name, category, frequency_days, next_due, priority, notes) values ($1, $2, $3, $4, $5, $6) returning id, created_at, updated_at `, t.Name, nullStr(t.Category), t.FrequencyDays, t.NextDue, t.Priority, nullStr(t.Notes)) created := t var model generatedmodels.ModelPublicMaintenanceTasks if err := row.Scan(&model.ID, &model.CreatedAt, &model.UpdatedAt); err != nil { return ext.MaintenanceTask{}, fmt.Errorf("insert maintenance task: %w", err) } created.ID = model.ID.UUID() created.CreatedAt = model.CreatedAt.Time() created.UpdatedAt = model.UpdatedAt.Time() return created, nil } func (db *DB) LogMaintenance(ctx context.Context, log ext.MaintenanceLog) (ext.MaintenanceLog, error) { completedAt := log.CompletedAt if completedAt.IsZero() { completedAt = time.Now() } row := db.pool.QueryRow(ctx, ` insert into maintenance_logs (task_id, completed_at, performed_by, cost, notes, next_action) values ($1, $2, $3, $4, $5, $6) returning id `, log.TaskID, completedAt, nullStr(log.PerformedBy), log.Cost, nullStr(log.Notes), nullStr(log.NextAction)) created := log created.CompletedAt = completedAt var model generatedmodels.ModelPublicMaintenanceLogs if err := row.Scan(&model.ID); err != nil { return ext.MaintenanceLog{}, fmt.Errorf("insert maintenance log: %w", err) } created.ID = model.ID.UUID() return created, nil } func (db *DB) GetUpcomingMaintenance(ctx context.Context, daysAhead int) ([]ext.MaintenanceTask, error) { if daysAhead <= 0 { daysAhead = 30 } cutoff := time.Now().Add(time.Duration(daysAhead) * 24 * time.Hour) rows, err := db.pool.Query(ctx, ` select id, name, category, frequency_days, last_completed, next_due, priority, notes, created_at, updated_at from maintenance_tasks where next_due <= $1 or next_due is null order by next_due asc nulls last, priority desc `, cutoff) if err != nil { return nil, fmt.Errorf("get upcoming maintenance: %w", err) } defer rows.Close() tasks := make([]ext.MaintenanceTask, 0) for rows.Next() { var model generatedmodels.ModelPublicMaintenanceTasks if err := rows.Scan(&model.ID, &model.Name, &model.Category, &model.FrequencyDays, &model.LastCompleted, &model.NextDue, &model.Priority, &model.Notes, &model.CreatedAt, &model.UpdatedAt); err != nil { return nil, fmt.Errorf("scan maintenance task: %w", err) } tasks = append(tasks, maintenanceTaskFromModel(model)) } return tasks, rows.Err() } func (db *DB) SearchMaintenanceHistory(ctx context.Context, query, category string, start, end *time.Time) ([]ext.MaintenanceLogWithTask, error) { args := []any{} conditions := []string{} if q := strings.TrimSpace(query); q != "" { args = append(args, "%"+q+"%") conditions = append(conditions, fmt.Sprintf("(mt.name ILIKE $%d OR ml.notes ILIKE $%d)", len(args), len(args))) } if c := strings.TrimSpace(category); c != "" { args = append(args, c) conditions = append(conditions, fmt.Sprintf("mt.category = $%d", len(args))) } if start != nil { args = append(args, *start) conditions = append(conditions, fmt.Sprintf("ml.completed_at >= $%d", len(args))) } if end != nil { args = append(args, *end) conditions = append(conditions, fmt.Sprintf("ml.completed_at <= $%d", len(args))) } q := ` select ml.id, ml.task_id, ml.completed_at, ml.performed_by, ml.cost, ml.notes, ml.next_action, mt.name, mt.category from maintenance_logs ml join maintenance_tasks mt on mt.id = ml.task_id ` if len(conditions) > 0 { q += " where " + strings.Join(conditions, " and ") } q += " order by ml.completed_at desc" rows, err := db.pool.Query(ctx, q, args...) if err != nil { return nil, fmt.Errorf("search maintenance history: %w", err) } defer rows.Close() var logs []ext.MaintenanceLogWithTask for rows.Next() { var model generatedmodels.ModelPublicMaintenanceLogs var taskName, taskCategory string if err := rows.Scan( &model.ID, &model.TaskID, &model.CompletedAt, &model.PerformedBy, &model.Cost, &model.Notes, &model.NextAction, &taskName, &taskCategory, ); err != nil { return nil, fmt.Errorf("scan maintenance log: %w", err) } l := ext.MaintenanceLogWithTask{ MaintenanceLog: maintenanceLogFromModel(model), TaskName: taskName, TaskCategory: taskCategory, } logs = append(logs, l) } return logs, rows.Err() }