package client

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

type AppTrackingEvent struct {
	AppCode         string          `json:"app_code"`
	EventID         string          `json:"event_id"`
	EventName       string          `json:"event_name"`
	EventType       string          `json:"event_type"`
	Screen          string          `json:"screen"`
	TargetType      string          `json:"target_type"`
	TargetID        string          `json:"target_id"`
	UserID          int64           `json:"user_id"`
	DeviceID        string          `json:"device_id"`
	SessionID       string          `json:"session_id"`
	ClientSessionID string          `json:"client_session_id"`
	AuthSessionID   string          `json:"auth_session_id"`
	Platform        string          `json:"platform"`
	AppVersion      string          `json:"app_version"`
	Language        string          `json:"language"`
	Timezone        string          `json:"timezone"`
	CountryID       int64           `json:"country_id"`
	RegionID        int64           `json:"region_id"`
	DurationMS      int64           `json:"duration_ms"`
	Success         bool            `json:"success"`
	ErrorCode       string          `json:"error_code"`
	Properties      json.RawMessage `json:"properties,omitempty"`
	OccurredAtMS    int64           `json:"occurred_at_ms"`
}

type AppTrackingReportResult struct {
	Accepted     bool  `json:"accepted"`
	Received     int   `json:"received"`
	Stored       int   `json:"stored"`
	Duplicated   int   `json:"duplicated"`
	ServerTimeMS int64 `json:"server_time_ms"`
}

type SelfGameH5Event struct {
	AppCode       string `json:"app_code"`
	EventID       string `json:"event_id"`
	EventName     string `json:"event_name"`
	GameID        string `json:"game_id"`
	Page          string `json:"page"`
	SessionID     string `json:"session_id"`
	MatchID       string `json:"match_id"`
	UserID        int64  `json:"user_id"`
	CountryID     int64  `json:"country_id"`
	RegionID      int64  `json:"region_id"`
	Language      string `json:"language"`
	ClientVersion string `json:"client_version"`
	H5Version     string `json:"h5_version"`
	EntrySource   string `json:"entry_source"`
	DurationMS    int64  `json:"duration_ms"`
	Success       bool   `json:"success"`
	ErrorCode     string `json:"error_code"`
	OccurredAtMS  int64  `json:"occurred_at_ms"`
}

type StatisticsClient interface {
	ReportSelfGameH5Event(ctx context.Context, event SelfGameH5Event) error
	ReportAppTrackingEvents(ctx context.Context, events []AppTrackingEvent) (AppTrackingReportResult, error)
}

type HTTPStatisticsClient struct {
	baseURL    string
	httpClient *http.Client
}

func NewHTTPStatisticsClient(baseURL string, timeout time.Duration) *HTTPStatisticsClient {
	baseURL = strings.TrimRight(strings.TrimSpace(baseURL), "/")
	if baseURL == "" {
		return nil
	}
	if timeout <= 0 {
		timeout = 2 * time.Second
	}
	return &HTTPStatisticsClient{
		baseURL:    baseURL,
		httpClient: &http.Client{Timeout: timeout},
	}
}

func (c *HTTPStatisticsClient) ReportSelfGameH5Event(ctx context.Context, event SelfGameH5Event) error {
	if c == nil || c.httpClient == nil || c.baseURL == "" {
		return fmt.Errorf("statistics client is not configured")
	}
	body, err := json.Marshal(event)
	if err != nil {
		return err
	}
	req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL+"/internal/v1/statistics/self-game/events", bytes.NewReader(body))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/json")
	resp, err := c.httpClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode >= 200 && resp.StatusCode < 300 {
		return nil
	}
	payload, _ := io.ReadAll(io.LimitReader(resp.Body, 512))
	return fmt.Errorf("statistics report failed: status=%d body=%s", resp.StatusCode, strings.TrimSpace(string(payload)))
}

func (c *HTTPStatisticsClient) ReportAppTrackingEvents(ctx context.Context, events []AppTrackingEvent) (AppTrackingReportResult, error) {
	if c == nil || c.httpClient == nil || c.baseURL == "" {
		return AppTrackingReportResult{}, fmt.Errorf("statistics client is not configured")
	}
	body, err := json.Marshal(map[string]any{"events": events})
	if err != nil {
		return AppTrackingReportResult{}, err
	}
	req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL+"/internal/v1/statistics/app/events", bytes.NewReader(body))
	if err != nil {
		return AppTrackingReportResult{}, err
	}
	req.Header.Set("Content-Type", "application/json")
	resp, err := c.httpClient.Do(req)
	if err != nil {
		return AppTrackingReportResult{}, err
	}
	defer resp.Body.Close()
	payload, _ := io.ReadAll(io.LimitReader(resp.Body, 4096))
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return AppTrackingReportResult{}, fmt.Errorf("statistics app event report failed: status=%d body=%s", resp.StatusCode, strings.TrimSpace(string(payload)))
	}
	var result AppTrackingReportResult
	if err := json.Unmarshal(payload, &result); err != nil {
		return AppTrackingReportResult{}, err
	}
	return result, nil
}
