package api

import (
	"encoding/json"
	"testing"
)

func TestChargerSourceByID(t *testing.T) {
	for _, id := range []string{ankerPlugin, greencellPlugin} {
		src, ok := chargerSourceByID(id)
		if !ok {
			t.Fatalf("charger provider %q is not registered", id)
		}
		if src.id() != id || src.label() == "" || src.service() == "" {
			t.Fatalf("provider %q describes itself badly: %+v", id, src)
		}
	}
	if _, ok := chargerSourceByID("toyota"); ok {
		t.Fatal("a vehicle provider must not resolve as a charger provider")
	}
}

// The Anker mapping reads the merged inventory the plugin's chargers capability
// answers with — the same document the Settings list renders.
func TestAnkerChargerSourceMapping(t *testing.T) {
	raw := json.RawMessage(`{"chargers":[
		{"sn":"AT2DK1","name":"Garage","model":"A5191","siteName":"Home","statusDesc":"charging","online":true,"sources":["site"]},
		{"sn":"AT2DK2","model":"A5191","online":false},
		{"sn":"","name":"nameless"}],"count":3}`)
	got := ankerChargerSource{}.chargers(raw)
	if len(got) != 2 {
		t.Fatalf("got %d chargers, want 2 (the serial-less one is skipped)", len(got))
	}
	first := got[0]
	if first.ID != "AT2DK1" || first.Name != "Garage" || first.Model != "A5191" {
		t.Fatalf("first charger = %+v", first)
	}
	if first.Vendor != "Anker Solix" || first.SiteName != "Home" || first.Status != "charging" {
		t.Fatalf("first charger not fully mapped: %+v", first)
	}
	if first.Online == nil || !*first.Online {
		t.Fatalf("online = %v, want true", first.Online)
	}
	if got[1].Online == nil || *got[1].Online {
		t.Fatalf("second charger online = %v, want false", got[1].Online)
	}
	if (ankerChargerSource{}).chargers(json.RawMessage(`not json`)) != nil {
		t.Fatal("a malformed payload should map to no chargers, not a panic")
	}
}

func TestGreencellChargerSourceMapping(t *testing.T) {
	raw := json.RawMessage(`{"chargers":[
		{"sn":"GC-1","name":"Wallbox","model":"HabuDen"},
		{"name":"no serial"}]}`)
	got := greencellChargerSource{}.chargers(raw)
	if len(got) != 1 {
		t.Fatalf("got %d chargers, want 1", len(got))
	}
	if got[0].ID != "GC-1" || got[0].Name != "Wallbox" || got[0].Vendor != "Greencell" {
		t.Fatalf("charger = %+v", got[0])
	}
}

func TestFindProviderCharger(t *testing.T) {
	list := []providerCharger{{ID: "AT2DK1"}, {ID: "GC-1"}}
	if _, ok := findProviderCharger(list, "  at2dk1 "); !ok {
		t.Fatal("a serial should match whatever case and padding it arrives in")
	}
	if _, ok := findProviderCharger(list, "AT2DK9"); ok {
		t.Fatal("a serial not on the account must not match")
	}
}

// The import payload carries the provider link and the owner; a later rename
// only ever touches the name, so the link cannot be broken by editing.
func TestHomeChargerPayloadOmitsProviderLink(t *testing.T) {
	payload := homeChargerPayload(homeChargerRecord{Name: "Garage", Serial: "AT2DK1"}.toModel())
	for _, key := range []string{"provider", "provider_charger_id", "owner"} {
		if _, present := payload[key]; present {
			t.Fatalf("payload must not carry %q — only the import endpoint sets it", key)
		}
	}
	if payload["name"] != "Garage" || payload["serial"] != "AT2DK1" {
		t.Fatalf("payload = %+v", payload)
	}
}

func TestHomeChargerRecordToModel(t *testing.T) {
	rec := homeChargerRecord{
		ID: "rec1", Name: "Garage", Serial: "AT2DK1", Vendor: "Anker Solix", Model: "A5191",
		SiteName: "Home", PowerKw: 11, Connector: "Type 2",
		Provider: ankerPlugin, ProviderChargerID: "AT2DK1", Owner: "u1", Created: "2026-08-31 10:00:00.000Z",
	}
	m := rec.toModel()
	if m.ID != "rec1" || m.Name != "Garage" || m.Serial != "AT2DK1" || m.PowerKw != 11 {
		t.Fatalf("model = %+v", m)
	}
	if m.Provider != ankerPlugin || m.ProviderChargerID != "AT2DK1" {
		t.Fatalf("provider link lost: %+v", m)
	}
	// The owner is not part of what a client reads back.
	b, err := json.Marshal(m)
	if err != nil {
		t.Fatal(err)
	}
	var out map[string]any
	if err := json.Unmarshal(b, &out); err != nil {
		t.Fatal(err)
	}
	if _, present := out["owner"]; present {
		t.Fatalf("home charger JSON should not carry an owner: %s", b)
	}
}
