package main

// Per-player profile aggregating known-player info, recent events, chat,
// warnings, and login stats into a single response.

import (
	"encoding/json"
	"net/http"
	"strconv"
)

// playerProfile is the top-level response shape.
type playerProfile struct {
	Known    *knownPlayerInfo   `json:"known,omitempty"`
	Events   []profileEvent     `json:"events"`
	Chat     []profileChatMsg   `json:"chat"`
	Warnings []profileWarning   `json:"warnings"`
	Stats    profileStats       `json:"stats"`
}

type knownPlayerInfo struct {
	PlayerID      int    `json:"playerId"`
	SteamID       string `json:"steamId"`
	PlayerName    string `json:"playerName"`
	FirstSeen     string `json:"firstSeen"`
	LastSeen      string `json:"lastSeen"`
	LoginCount    int    `json:"loginCount"`
	LastPlayfield string `json:"lastPlayfield"`
	Notes         string `json:"notes"`
}

type profileEvent struct {
	TS         string `json:"ts"`
	Cmd        string `json:"cmd"`
	Playfield  string `json:"playfield,omitempty"`
	Msg        string `json:"msg,omitempty"`
}

type profileChatMsg struct {
	TS         string `json:"ts"`
	PlayerName string `json:"playerName,omitempty"`
	Msg        string `json:"msg"`
	Channel    int    `json:"channel"`
}

type profileWarning struct {
	ID         int64  `json:"id"`
	Reason     string `json:"reason"`
	GivenBy    string `json:"givenBy,omitempty"`
	AutoRule   string `json:"autoRule,omitempty"`
	GivenAt    string `json:"givenAt"`
}

type profileStats struct {
	LoginCount  int    `json:"loginCount"`
	LastSeen    string `json:"lastSeen"`
	TotalEvents int    `json:"totalEvents"`
}

// ---------------------------------------------------------------------------
// GET /api/instances/{id}/empyrion-history/players/{playerId}/profile
// ---------------------------------------------------------------------------

func (h *httpServer) handleEmpyrionPlayerProfile(w http.ResponseWriter, r *http.Request) {
	instanceID := r.PathValue("id")
	playerID, err := strconv.Atoi(r.PathValue("playerId"))
	if err != nil || playerID <= 0 {
		writeError(w, http.StatusBadRequest, "bad_player_id", "playerId must be a positive integer")
		return
	}

	ctx := r.Context()
	prof := playerProfile{
		Events:   []profileEvent{},
		Chat:     []profileChatMsg{},
		Warnings: []profileWarning{},
	}

	// 1. Known-player info.
	var kp knownPlayerInfo
	var firstSeen, lastSeen any
	err = h.db.Pool().QueryRow(ctx, `
		SELECT player_id, steam_id, player_name, first_seen, last_seen,
		       login_count, last_playfield, notes
		FROM empyrion_known_players
		WHERE instance_id = $1 AND player_id = $2`,
		instanceID, playerID,
	).Scan(&kp.PlayerID, &kp.SteamID, &kp.PlayerName, &firstSeen, &lastSeen,
		&kp.LoginCount, &kp.LastPlayfield, &kp.Notes)
	if err == nil {
		kp.FirstSeen = formatTS(firstSeen)
		kp.LastSeen = formatTS(lastSeen)
		prof.Known = &kp
		prof.Stats.LoginCount = kp.LoginCount
		prof.Stats.LastSeen = kp.LastSeen
	}

	// 2. Last 50 events.
	{
		rows, qerr := h.db.Pool().Query(ctx, `
			SELECT ts, cmd, COALESCE(playfield,''), COALESCE(msg,'')
			FROM empyrion_events
			WHERE instance_id = $1 AND player_id = $2
			ORDER BY ts DESC LIMIT 50`,
			instanceID, playerID)
		if qerr == nil {
			defer rows.Close()
			for rows.Next() {
				var e profileEvent
				var ts any
				if err := rows.Scan(&ts, &e.Cmd, &e.Playfield, &e.Msg); err != nil {
					continue
				}
				e.TS = formatTS(ts)
				prof.Events = append(prof.Events, e)
			}
		}
	}

	// 3. Last 50 chat messages.
	{
		rows, qerr := h.db.Pool().Query(ctx, `
			SELECT ts, COALESCE(player_name,''), COALESCE(msg,''), raw
			FROM empyrion_events
			WHERE instance_id = $1 AND player_id = $2
			  AND cmd IN ('Event_ChatMessage','Event_ChatMessageEx')
			ORDER BY ts DESC LIMIT 50`,
			instanceID, playerID)
		if qerr == nil {
			defer rows.Close()
			for rows.Next() {
				var c profileChatMsg
				var ts any
				var raw []byte
				if err := rows.Scan(&ts, &c.PlayerName, &c.Msg, &raw); err != nil {
					continue
				}
				c.TS = formatTS(ts)
				// Extract channel type from raw JSON.
				var d struct {
					Type int `json:"type"`
				}
				_ = json.Unmarshal(raw, &d)
				c.Channel = d.Type
				prof.Chat = append(prof.Chat, c)
			}
		}
	}

	// 4. Last 50 warnings.
	{
		rows, qerr := h.db.Pool().Query(ctx, `
			SELECT id, reason, COALESCE(given_by,''), COALESCE(auto_rule,''), given_at
			FROM empyrion_warnings
			WHERE instance_id = $1 AND player_id = $2
			ORDER BY given_at DESC LIMIT 50`,
			instanceID, playerID)
		if qerr == nil {
			defer rows.Close()
			for rows.Next() {
				var w profileWarning
				var givenAt any
				if err := rows.Scan(&w.ID, &w.Reason, &w.GivenBy, &w.AutoRule, &givenAt); err != nil {
					continue
				}
				w.GivenAt = formatTS(givenAt)
				prof.Warnings = append(prof.Warnings, w)
			}
		}
	}

	// 5. Total event count (best-effort session stats).
	{
		var totalEvents int
		err = h.db.Pool().QueryRow(ctx, `
			SELECT count(*) FROM empyrion_events
			WHERE instance_id = $1 AND player_id = $2`,
			instanceID, playerID).Scan(&totalEvents)
		if err == nil {
			prof.Stats.TotalEvents = totalEvents
		}
	}

	writeJSON(w, http.StatusOK, prof)
}
