package handler

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"io"
	"math/rand"
	"mocksnow/db/queries"
	"mocksnow/server/models"
	"net/http"
	"os"

	"github.com/google/uuid"
)

// NewSnow receives data from the DMSP Snow New() function
func (h *Handler) NewSnow(w http.ResponseWriter, r *http.Request) {
	var hostname string

	reqBody, err := io.ReadAll(r.Body)
	if err != nil {
		h.Logger.Error("Invalid data received", "error", err)
		fmt.Fprintf(w, "Invalid data received")
		w.WriteHeader(http.StatusInternalServerError)
		return
	} else {
		h.Logger.Debug("received input data", "length", len(reqBody))
	}

	// Decode the JSON body
	var incident models.Incident
	if err := json.Unmarshal(reqBody, &incident); err != nil {
		h.Logger.Error("unable to decode json", "error", err)
		http.Error(w, "Invalid JSON body", http.StatusBadRequest)
		return
	} else {
		h.Logger.Debug("successfully decoded JSON")
		prettyPrint(incident)
	}

	ctx := r.Context()

	// 1. Insert into incoming table
	params := queries.CreateIncomingParams{
		IncidentNumber:   nullStr(incident.IncidentNumber),
		Description:      nullStr(incident.Description),
		ShortDescription: nullStr(incident.ShortDescription),
		Urgency:          nullStr(incident.Urgency),
		Impact:           nullStr(incident.Impact),
		State:            nullStr(incident.State),
		ExternalID:       nullStr(incident.ExternalID),
		WorkNotes:        nullStr(incident.WorkNotes),
		AssignmentGroup:  nullStr(incident.AssignmentGroup),
		AssignedTo:       nullStr(incident.AssignedTo),
		Category:         nullStr(incident.Category),
		Subcategory:      nullStr(incident.SubCategory),
	}

	h.Logger.Debug("database params", "params", params)

	// Insert the new inventory record into the database
	result, err := h.Database.Queries().CreateIncoming(ctx, params)
	if err != nil {
		h.Logger.Error("unable to perform database insert", "error", err)
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "Error : %v\n", err)
		return
	} else {
		h.Logger.Debug("created database record", "insert_result", result)
	}

	// Create record in incidents table
	incidentRecord, err := h.Database.Queries().CreateIncident(ctx, incident.ExternalID)
	if err != nil {
		h.Logger.Error("failed to create incident", "error", err)
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "Error : %v\n", err)
		return
	} else {
		h.Logger.Debug("created database record", "incident_record", incidentRecord)
	}

	// Simulate response
	ticket := fmt.Sprintf("TKT%06d", incidentRecord)
	sysID := uuid.New().String()

	// Produce dummy record link
	hostname, err = os.Hostname()
	if err != nil {
		h.Logger.Error("failed to lookup hostname", "error", err)
		hostname = "localhost"
	}

	recordLink := fmt.Sprintf("https://%s/api/now/table/incident/%s", hostname, sysID)

	response := models.IncidentResponse{
		ImportSet:    randomImportSet(),
		StagingTable: "x_dusa2_itom_inc_imp",
		Result: []models.IncidentResultItem{
			{
				TransformMap: "Incident Import",
				Table:        "incident",
				DisplayName:  "number",
				DisplayValue: ticket,
				RecordLink:   recordLink,
				Status:       "inserted",
				SysID:        sysID,
			},
		},
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(response)
}

func nullStr(s string) sql.NullString {
	return sql.NullString{String: s, Valid: s != ""}
}

// Helper to generate random import_set ID
func randomImportSet() string {
	const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	b := make([]byte, 8)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}
