package subsonic

import (
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq"
)

func TestHandleGetUser_Self(t *testing.T) {
	user := dbq.User{Username: "alice", IsAdmin: false}
	w, body := callGetUser(t, user, "")

	if w.Code != http.StatusOK {
		t.Fatalf("status = %d, want 200", w.Code)
	}
	if body.Resp.Status != "ok" {
		t.Errorf("status = %q, want ok", body.Resp.Status)
	}
	if body.Resp.User.Username != "alice" {
		t.Errorf("username = %q, want alice", body.Resp.User.Username)
	}
	if body.Resp.User.AdminRole {
		t.Error("non-admin should not have admin role")
	}
	if !body.Resp.User.StreamRole {
		t.Error("stream role must be on so clients enable playback")
	}
}

func TestHandleGetUser_AdminGetsAdminRole(t *testing.T) {
	admin := dbq.User{Username: "admin", IsAdmin: true}
	_, body := callGetUser(t, admin, "")
	if !body.Resp.User.AdminRole || !body.Resp.User.SettingsRole {
		t.Errorf("admin/settings roles = %v/%v, want true/true",
			body.Resp.User.AdminRole, body.Resp.User.SettingsRole)
	}
}

func TestHandleGetUser_NonAdminCannotLookupOthers(t *testing.T) {
	user := dbq.User{Username: "alice", IsAdmin: false}
	_, body := callGetUser(t, user, "bob")
	if body.Resp.Status != "failed" || body.Resp.Error == nil ||
		body.Resp.Error.Code != ErrNotAuthorized {
		t.Errorf("expected ErrNotAuthorized, got status=%q err=%+v",
			body.Resp.Status, body.Resp.Error)
	}
}

type getUserPayload struct {
	Resp struct {
		Status string `json:"status"`
		Error  *Error `json:"error"`
		User   User   `json:"user"`
	} `json:"subsonic-response"`
}

func callGetUser(t *testing.T, user dbq.User, requestedUsername string) (*httptest.ResponseRecorder, getUserPayload) {
	t.Helper()
	url := "/rest/getUser.view?f=json"
	if requestedUsername != "" {
		url += "&username=" + requestedUsername
	}
	req := httptest.NewRequest("GET", url, nil)
	req = req.WithContext(context.WithValue(req.Context(), userCtxKey, user))
	w := httptest.NewRecorder()
	handleGetUser(w, req)

	var body getUserPayload
	if err := json.NewDecoder(strings.NewReader(w.Body.String())).Decode(&body); err != nil {
		t.Fatalf("decode response: %v\nbody=%s", err, w.Body.String())
	}
	return w, body
}
