package subsonic

import (
	"encoding/xml"
	"net/http"

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

// UserResponse wraps the User payload Subsonic clients fetch right after
// login to discover what the authenticated identity can do. Feishin uses
// this to gate UI affordances; without it the login flow stalls.
type UserResponse struct {
	Envelope
	User User `json:"user" xml:"user"`
}

// User mirrors the role-bag from the Subsonic spec. We expose the full set
// even though Minstrel doesn't model fine-grained ACLs yet — admins get
// every role, non-admins get the "play music" subset. This keeps clients
// from disabling features they could otherwise use.
type User struct {
	XMLName             xml.Name `json:"-" xml:"user"`
	Username            string   `json:"username" xml:"username,attr"`
	Email               string   `json:"email,omitempty" xml:"email,attr,omitempty"`
	ScrobblingEnabled   bool     `json:"scrobblingEnabled" xml:"scrobblingEnabled,attr"`
	AdminRole           bool     `json:"adminRole" xml:"adminRole,attr"`
	SettingsRole        bool     `json:"settingsRole" xml:"settingsRole,attr"`
	DownloadRole        bool     `json:"downloadRole" xml:"downloadRole,attr"`
	UploadRole          bool     `json:"uploadRole" xml:"uploadRole,attr"`
	PlaylistRole        bool     `json:"playlistRole" xml:"playlistRole,attr"`
	CoverArtRole        bool     `json:"coverArtRole" xml:"coverArtRole,attr"`
	CommentRole         bool     `json:"commentRole" xml:"commentRole,attr"`
	PodcastRole         bool     `json:"podcastRole" xml:"podcastRole,attr"`
	StreamRole          bool     `json:"streamRole" xml:"streamRole,attr"`
	JukeboxRole         bool     `json:"jukeboxRole" xml:"jukeboxRole,attr"`
	ShareRole           bool     `json:"shareRole" xml:"shareRole,attr"`
	VideoConversionRole bool     `json:"videoConversionRole" xml:"videoConversionRole,attr"`
}

// handleGetUser returns the authenticated user when no username is provided
// or when the requested username matches; admins may look up any user. Per
// spec a non-admin asking about another user gets ErrNotAuthorized.
func handleGetUser(w http.ResponseWriter, r *http.Request) {
	caller, ok := UserFromContext(r.Context())
	if !ok {
		WriteFail(w, r, ErrNotAuthorized, "Not authenticated")
		return
	}
	requested := r.URL.Query().Get("username")
	if requested != "" && requested != caller.Username && !caller.IsAdmin {
		WriteFail(w, r, ErrNotAuthorized, "Not authorized to view other users")
		return
	}
	// We don't have a per-user lookup wired up yet; until then admins asking
	// for another username see the caller's roles. Acceptable while M1 has a
	// single user; revisit once user management lands.
	Write(w, r, UserResponse{
		Envelope: NewEnvelope("ok"),
		User:     userPayload(caller),
	})
}

func userPayload(u dbq.User) User {
	return User{
		Username:          u.Username,
		ScrobblingEnabled: true,
		AdminRole:         u.IsAdmin,
		SettingsRole:      u.IsAdmin,
		DownloadRole:      true,
		UploadRole:        false,
		PlaylistRole:      true,
		CoverArtRole:      true,
		CommentRole:       false,
		PodcastRole:       false,
		StreamRole:        true,
		JukeboxRole:       false,
		ShareRole:         false,
	}
}
