package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"regexp"
)

type Property struct {
	Name      string `json:"name"`
	Value     string `json:"value"`
	Signature string `json:"signature"`
}

type MCPlayer struct {
	Username    string
	UUID        string
	AvatarURL   string
	SkinTexture string
	Properties  []Property
}

func isValidUUID(id string) bool {
	r := regexp.MustCompile(`^[a-fA-F0-9]{32}$|^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$`)
	return r.MatchString(id)
}

func isValidUsername(name string) bool {
	r := regexp.MustCompile(`^[a-zA-Z0-9_]{3,16}$`)
	return r.MatchString(name)
}

func fetchFromPlayerDB(id string) (*MCPlayer, error) {
	url := fmt.Sprintf("https://playerdb.co/api/player/minecraft/%s", id)

	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	var result map[string]interface{}
	err = json.Unmarshal(body, &result)
	if err != nil {
		return nil, err
	}

	if result["success"].(bool) == false {
		return nil, fmt.Errorf("player not found (playerdb): %s", id)
	}

	data := result["data"].(map[string]interface{})
	player := data["player"].(map[string]interface{})
	properties := player["properties"].([]interface{})

	mcPlayer := &MCPlayer{
		Username:    player["username"].(string),
		UUID:        player["id"].(string),
		AvatarURL:   player["avatar"].(string),
		SkinTexture: player["skin_texture"].(string),
	}

	for _, p := range properties {
		prop := p.(map[string]interface{})
		mcPlayer.Properties = append(mcPlayer.Properties, Property{
			Name:      prop["name"].(string),
			Value:     prop["value"].(string),
			Signature: prop["signature"].(string),
		})
	}

	return mcPlayer, nil
}

func FetchMCPlayer(id string) (*MCPlayer, error) {
	// TODO: Implement mojang API as the fallback
	// TODO: Catch Nicks (propagate nick catcher through to HypixelAPI)
	if isValidUUID(id) {
		player, err := fetchFromPlayerDB(id)
		if err != nil {
			return nil, err
		}
		return player, nil
	} else if isValidUsername(id) {
		player, err := fetchFromPlayerDB(id)
		if err != nil {
			return nil, err
		}
		return player, nil
	} else {
		return nil, errors.New("invalid input: not a valid UUID or username")
	}
}
