// bobcord_go.go — SDK BobCord (REST + builders)
// User + Bot + EmbedBuilder + ActionRow / Button / WebAction
// API: https://aml-s9xx-box.taildd440a.ts.net/api/v1.1
// package: mets ce fichier dans ton module (package main ou bobcord)

package bobcord

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"
)

const DefaultBase = "https://aml-s9xx-box.taildd440a.ts.net/api/v1.1"

type M = map[string]any

func WebActionConfirm(title, body string, then M) M {
	o := M{"type": "confirm", "title": title, "body": body}
	if then != nil {
		o["then"] = then
	}
	return o
}

func WebActionSendMessage(content string, channel string, serverID any, confirm M) M {
	o := M{"type": "send_message", "content": content}
	if channel != "" {
		o["channel"] = channel
	}
	if serverID != nil {
		o["server_id"] = serverID
	}
	if confirm != nil {
		o["confirm"] = confirm
	}
	return o
}

func WebActionReact(emoji string, messageID any, confirm M) M {
	if messageID == nil {
		messageID = "self"
	}
	o := M{"type": "react", "emoji": emoji, "message_id": messageID}
	if confirm != nil {
		o["confirm"] = confirm
	}
	return o
}

func Button(label, style, customID string) M {
	return M{"type": "BUTTON", "style": strings.ToUpper(style), "label": label, "custom_id": customID, "disabled": false}
}

func ButtonLink(label, url string) M {
	return M{"type": "BUTTON", "style": "LINK", "label": label, "url": url, "disabled": false}
}

func ButtonWebAction(label, customID string, webAction M) M {
	return M{"type": "BUTTON", "style": "WEB_ACTION", "label": label, "custom_id": customID, "web_action": webAction, "disabled": false}
}

func ActionRow(components ...M) M {
	comps := []M{}
	for i, c := range components {
		if i >= 5 {
			break
		}
		comps = append(comps, c)
	}
	return M{"type": "ACTION_ROW", "components": comps}
}

func ActionRows(rows ...M) []M {
	if len(rows) > 4 {
		rows = rows[:4]
	}
	return rows
}

type EmbedBuilder struct{ data M }

func NewEmbedBuilder() *EmbedBuilder {
	return &EmbedBuilder{data: M{"fields": []any{}}}
}
func (e *EmbedBuilder) Title(t string) *EmbedBuilder       { e.data["title"] = t; return e }
func (e *EmbedBuilder) Description(d string) *EmbedBuilder { e.data["description"] = d; return e }
func (e *EmbedBuilder) Color(c int) *EmbedBuilder          { e.data["color"] = c & 0xFFFFFF; return e }
func (e *EmbedBuilder) AddField(name, value string, inline bool) *EmbedBuilder {
	fields := e.data["fields"].([]any)
	e.data["fields"] = append(fields, M{"name": name, "value": value, "inline": inline})
	return e
}
func (e *EmbedBuilder) Footer(text string) *EmbedBuilder { e.data["footer"] = M{"text": text}; return e }
func (e *EmbedBuilder) Build() M                         { return e.data }

type User struct {
	Token   string
	BaseURL string
	Me      M
	client  *http.Client
}

func NewUser(token string) *User {
	return &User{Token: strings.TrimSpace(token), BaseURL: DefaultBase, client: &http.Client{}}
}

func (u *User) Request(method, path string, body any) (M, error) {
	url := strings.TrimRight(u.BaseURL, "/") + "/" + strings.TrimLeft(path, "/")
	var rdr io.Reader
	if body != nil {
		b, err := json.Marshal(body)
		if err != nil {
			return nil, err
		}
		rdr = bytes.NewReader(b)
	}
	req, err := http.NewRequest(method, url, rdr)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Authorization", "Bearer "+u.Token)
	req.Header.Set("Content-Type", "application/json")
	res, err := u.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()
	raw, _ := io.ReadAll(res.Body)
	if res.StatusCode == 204 {
		return nil, nil
	}
	var data M
	_ = json.Unmarshal(raw, &data)
	if res.StatusCode >= 400 {
		return data, fmt.Errorf("HTTP %d: %v", res.StatusCode, data["error"])
	}
	return data, nil
}

func (u *User) Login() (M, error) {
	data, err := u.Request("GET", "/me", nil)
	if err != nil {
		return nil, err
	}
	if user, ok := data["user"].(map[string]any); ok {
		u.Me = user
	} else {
		u.Me = data
	}
	return u.Me, nil
}

type SendOpts struct {
	ServerID    int
	Embeds      []M
	ActionRows  []M
	Attachments any
}

func (u *User) Send(content, channel string, opts *SendOpts) (M, error) {
	if opts == nil {
		opts = &SendOpts{ServerID: 1}
	}
	if opts.ServerID == 0 {
		opts.ServerID = 1
	}
	body := M{"content": content, "channel": channel, "server_id": opts.ServerID}
	if opts.Embeds != nil {
		body["embeds"] = opts.Embeds
	}
	if opts.Attachments != nil {
		body["attachments"] = opts.Attachments
	}
	if opts.ActionRows != nil {
		body["action_rows"] = opts.ActionRows
	}
	return u.Request("POST", "/message", body)
}

type Bot struct{ *User }

func NewBot(token string) *Bot { return &Bot{User: NewUser(token)} }
