package handler import ( "context" "encoding/json" "fmt" "net/http" "net/url" "strings" "vctp/components/views" "vctp/internal/report" "github.com/a-h/templ" ) // SnapshotHourlyList renders the hourly snapshot list page. // @Summary List hourly snapshots // @Description Lists hourly inventory snapshot tables. // @Tags snapshots // @Produce text/html // @Success 200 {string} string "HTML page" // @Failure 500 {string} string "Server error" // @Router /snapshots/hourly [get] func (h *Handler) SnapshotHourlyList(w http.ResponseWriter, r *http.Request) { h.renderSnapshotList(w, r, "inventory_daily_", "Hourly Inventory Snapshots", views.SnapshotHourlyList) } // SnapshotDailyList renders the daily snapshot list page. // @Summary List daily snapshots // @Description Lists daily summary snapshot tables. // @Tags snapshots // @Produce text/html // @Success 200 {string} string "HTML page" // @Failure 500 {string} string "Server error" // @Router /snapshots/daily [get] func (h *Handler) SnapshotDailyList(w http.ResponseWriter, r *http.Request) { h.renderSnapshotList(w, r, "inventory_daily_summary_", "Daily Inventory Snapshots", views.SnapshotDailyList) } // SnapshotMonthlyList renders the monthly snapshot list page. // @Summary List monthly snapshots // @Description Lists monthly summary snapshot tables. // @Tags snapshots // @Produce text/html // @Success 200 {string} string "HTML page" // @Failure 500 {string} string "Server error" // @Router /snapshots/monthly [get] func (h *Handler) SnapshotMonthlyList(w http.ResponseWriter, r *http.Request) { h.renderSnapshotList(w, r, "inventory_monthly_summary_", "Monthly Inventory Snapshots", views.SnapshotMonthlyList) } // SnapshotReportDownload streams a snapshot table as XLSX. // @Summary Download snapshot report // @Description Downloads a snapshot table as an XLSX file. // @Tags snapshots // @Produce application/vnd.openxmlformats-officedocument.spreadsheetml.sheet // @Param table query string true "Snapshot table name" // @Success 200 {file} file "Snapshot XLSX report" // @Failure 400 {object} map[string]string "Invalid request" // @Failure 500 {object} map[string]string "Server error" // @Router /api/report/snapshot [get] func (h *Handler) SnapshotReportDownload(w http.ResponseWriter, r *http.Request) { ctx := context.Background() tableName := r.URL.Query().Get("table") if tableName == "" { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusBadRequest) json.NewEncoder(w).Encode(map[string]string{ "status": "ERROR", "message": "Missing table parameter", }) return } reportData, err := report.CreateTableReport(h.Logger, h.Database, ctx, tableName) if err != nil { h.Logger.Error("Failed to create snapshot report", "error", err, "table", tableName) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) json.NewEncoder(w).Encode(map[string]string{ "status": "ERROR", "message": fmt.Sprintf("Unable to create snapshot report: '%s'", err), }) return } filename := fmt.Sprintf("%s.xlsx", tableName) w.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename)) w.Header().Set("File-Name", filename) w.Write(reportData) } func (h *Handler) renderSnapshotList(w http.ResponseWriter, r *http.Request, prefix string, title string, renderer func([]views.SnapshotEntry) templ.Component) { ctx := context.Background() tables, err := report.ListTablesByPrefix(ctx, h.Database, prefix) if err != nil { h.Logger.Error("Failed to list snapshot tables", "error", err, "prefix", prefix) w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, "Unable to list snapshot tables: %s\n", err) return } entries := make([]views.SnapshotEntry, 0, len(tables)) for _, table := range tables { if prefix == "inventory_daily_" && strings.HasPrefix(table, "inventory_daily_summary_") { continue } label := table if parsed, ok := report.FormatSnapshotLabel(prefix, table); ok { label = parsed } entries = append(entries, views.SnapshotEntry{ Label: label, Link: "/api/report/snapshot?table=" + url.QueryEscape(table), }) } if err := renderer(entries).Render(r.Context(), w); err != nil { h.Logger.Error("Failed to render snapshot list", "error", err, "title", title) w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, "Failed to render snapshot list") } }