package api

// A home charger is the wallbox a user owns, stored the way a car is: a record
// of their own, listed on the Charging page, kept after the account it came from
// is disconnected. It belongs to the person rather than to a car — it charges
// whichever car is plugged into it, and it outlives any of them — so there is no
// car relation here and no sharing: everyone sees their own chargers only.
//
//	GET    /api/home-chargers        — the caller's chargers
//	PATCH  /api/home-chargers/{id}   — rename one
//	DELETE /api/home-chargers/{id}   — forget one
//
// Creating one is the business of chargerproviders.go: a charger is imported
// from a service the user has connected, the same move the garage makes for a
// car. Nothing here writes the provider link, so a rename cannot silently break
// it.

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strings"

	"drivervault/apiserver/internal/models"
)

// homeChargerRecord is the PocketBase-facing shape of a home charger.
type homeChargerRecord struct {
	ID                string  `json:"id"`
	Name              string  `json:"name"`
	Serial            string  `json:"serial"`
	Vendor            string  `json:"vendor"`
	Model             string  `json:"model"`
	SiteName          string  `json:"site_name"`
	PowerKw           float64 `json:"power_kw"`
	Connector         string  `json:"connector"`
	Provider          string  `json:"provider"`
	ProviderChargerID string  `json:"provider_charger_id"`
	Owner             string  `json:"owner"`
	Created           string  `json:"created"`
}

func (rec homeChargerRecord) toModel() models.HomeCharger {
	return models.HomeCharger{
		ID:                rec.ID,
		Name:              rec.Name,
		Serial:            rec.Serial,
		Vendor:            rec.Vendor,
		Model:             rec.Model,
		SiteName:          rec.SiteName,
		PowerKw:           rec.PowerKw,
		Connector:         rec.Connector,
		Provider:          rec.Provider,
		ProviderChargerID: rec.ProviderChargerID,
		Created:           rec.Created,
	}
}

// homeChargerPayload is the write shape. The provider link is not part of it:
// only the import endpoint sets that, and it adds those two fields itself.
func homeChargerPayload(c models.HomeCharger) map[string]any {
	return map[string]any{
		"name":      c.Name,
		"serial":    c.Serial,
		"vendor":    c.Vendor,
		"model":     c.Model,
		"site_name": c.SiteName,
		"power_kw":  c.PowerKw,
		"connector": c.Connector,
	}
}

// listHomeChargers returns the caller's own chargers, newest first — the order
// they were imported in, which is the order they were installed in often enough.
func (s *Server) listHomeChargers(w http.ResponseWriter, r *http.Request) {
	me := s.currentUserID(r)
	if me == "" {
		writeError(w, http.StatusUnauthorized, "not authenticated")
		return
	}
	query := func(sort string) url.Values {
		q := url.Values{
			"filter":  {fmt.Sprintf("owner='%s'", me)},
			"perPage": {"200"},
		}
		if sort != "" {
			q.Set("sort", sort)
		}
		return q
	}
	res, err := s.pb.List(r.Context(), colHomeChargers, query("created"))
	if err != nil {
		// A collection created before `created` was declared does not have the
		// field, and PocketBase rejects the whole query over an unknown sort. The
		// order is a nicety; the list is not, so ask again without it rather than
		// show the owner an error about a field they cannot see. The bootstrap
		// adds the field on the next boot, and the sorted query then wins.
		res, err = s.pb.List(r.Context(), colHomeChargers, query(""))
	}
	if err != nil {
		writePBError(w, err)
		return
	}
	var recs []homeChargerRecord
	if err := json.Unmarshal(res.Items, &recs); err != nil {
		writeError(w, http.StatusInternalServerError, err.Error())
		return
	}
	out := make([]models.HomeCharger, 0, len(recs))
	for _, rec := range recs {
		out = append(out, rec.toModel())
	}
	writeJSON(w, http.StatusOK, map[string]any{"chargers": out})
}

// ownedHomeCharger fetches one charger and checks it is the caller's. It writes
// the error response itself and returns ok=false when it is not.
func (s *Server) ownedHomeCharger(w http.ResponseWriter, r *http.Request) (homeChargerRecord, bool) {
	var rec homeChargerRecord
	id := strings.TrimSpace(r.PathValue("id"))
	if id == "" {
		writeError(w, http.StatusBadRequest, "charger id is required")
		return rec, false
	}
	if err := s.pb.GetOne(r.Context(), colHomeChargers, id, &rec); err != nil {
		writePBError(w, err)
		return rec, false
	}
	// Someone else's charger is not found rather than forbidden: whether a record
	// exists is not this caller's business either.
	if rec.Owner != s.currentUserID(r) {
		writeError(w, http.StatusNotFound, "charger not found")
		return rec, false
	}
	return rec, true
}

// updateHomeCharger renames a charger. Only the name is editable — everything
// else describes the hardware and comes from the service it was imported from.
func (s *Server) updateHomeCharger(w http.ResponseWriter, r *http.Request) {
	rec, ok := s.ownedHomeCharger(w, r)
	if !ok {
		return
	}
	var body struct {
		Name string `json:"name"`
	}
	if err := decodeJSON(r, &body); err != nil {
		writeError(w, http.StatusBadRequest, err.Error())
		return
	}
	name := strings.TrimSpace(body.Name)
	if name == "" {
		writeError(w, http.StatusBadRequest, "name is required")
		return
	}
	var updated homeChargerRecord
	if err := s.pb.Update(r.Context(), colHomeChargers, rec.ID, map[string]any{"name": name}, &updated); err != nil {
		writePBError(w, err)
		return
	}
	writeJSON(w, http.StatusOK, map[string]any{"charger": updated.toModel()})
}

// deleteHomeCharger forgets a charger. The charger itself is untouched — this is
// a record about it, and importing it again brings it straight back.
func (s *Server) deleteHomeCharger(w http.ResponseWriter, r *http.Request) {
	rec, ok := s.ownedHomeCharger(w, r)
	if !ok {
		return
	}
	if err := s.pb.Delete(r.Context(), colHomeChargers, rec.ID); err != nil {
		writePBError(w, err)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}
