package statisticsclient

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

type ActivityTemplateDataQuery struct {
	AppCode          string
	TemplateID       string
	PublishedVersion int64
	RegionID         int64
	StartMS          int64
	EndMS            int64
}

type ActivityTemplateOverview struct {
	TemplateID       string `json:"template_id"`
	TemplateCode     string `json:"template_code"`
	PublishedVersion int64  `json:"published_version"`
	Participants     int64  `json:"participants"`
	VisitCount       int64  `json:"visit_count"`
	GiftUsers        int64  `json:"gift_users"`
	TaskUsers        int64  `json:"task_users"`
	GiftEventCount   int64  `json:"gift_event_count"`
	GiftCount        int64  `json:"gift_count"`
	CoinAmount       int64  `json:"coin_amount"`
	TaskProgress     int64  `json:"task_progress"`
	TaskCompleted    int64  `json:"task_completed"`
	TaskClaimed      int64  `json:"task_claimed"`
}

type ActivityTemplateTrendPoint struct {
	StatDay        string `json:"stat_day"`
	Participants   int64  `json:"participants"`
	VisitCount     int64  `json:"visit_count"`
	GiftUsers      int64  `json:"gift_users"`
	TaskUsers      int64  `json:"task_users"`
	GiftEventCount int64  `json:"gift_event_count"`
	GiftCount      int64  `json:"gift_count"`
	CoinAmount     int64  `json:"coin_amount"`
	TaskProgress   int64  `json:"task_progress"`
	TaskCompleted  int64  `json:"task_completed"`
	TaskClaimed    int64  `json:"task_claimed"`
}

type ActivityTemplateGiftStat struct {
	GiftID         string `json:"gift_id"`
	GiftUsers      int64  `json:"gift_users"`
	GiftEventCount int64  `json:"gift_event_count"`
	GiftCount      int64  `json:"gift_count"`
	CoinAmount     int64  `json:"coin_amount"`
}

type ActivityTemplateTaskStat struct {
	TaskKey       string `json:"task_key"`
	TaskType      string `json:"task_type"`
	TaskUsers     int64  `json:"task_users"`
	TaskProgress  int64  `json:"task_progress"`
	TaskCompleted int64  `json:"task_completed"`
	TaskClaimed   int64  `json:"task_claimed"`
}

// ActivityTemplateData mirrors statistics-service's aggregate-only read model.
// Admin intentionally does not reconstruct any of these counters from activity owner tables.
type ActivityTemplateData struct {
	Overview       ActivityTemplateOverview     `json:"overview"`
	Trend          []ActivityTemplateTrendPoint `json:"trend"`
	Gifts          []ActivityTemplateGiftStat   `json:"gifts"`
	Tasks          []ActivityTemplateTaskStat   `json:"tasks"`
	Granularity    string                       `json:"granularity"`
	Timezone       string                       `json:"timezone"`
	StartMS        int64                        `json:"start_ms"`
	EndMS          int64                        `json:"end_ms"`
	RegionID       int64                        `json:"region_id"`
	DimensionLimit int                          `json:"dimension_limit"`
	GiftSort       string                       `json:"gift_sort"`
	TaskSort       string                       `json:"task_sort"`
	ServerTimeMS   int64                        `json:"server_time_ms"`
}

type ActivityTemplateDataClient interface {
	ActivityTemplateData(context.Context, ActivityTemplateDataQuery) (ActivityTemplateData, error)
}

type HTTPClient struct {
	baseURL string
	client  *http.Client
}

func NewHTTP(baseURL string, timeout time.Duration) *HTTPClient {
	if timeout <= 0 {
		timeout = 3 * time.Second
	}
	return &HTTPClient{
		baseURL: strings.TrimRight(strings.TrimSpace(baseURL), "/"),
		client:  &http.Client{Timeout: timeout},
	}
}

func (c *HTTPClient) ActivityTemplateData(ctx context.Context, query ActivityTemplateDataQuery) (ActivityTemplateData, error) {
	values := url.Values{}
	values.Set("app_code", strings.TrimSpace(query.AppCode))
	values.Set("template_id", strings.TrimSpace(query.TemplateID))
	values.Set("published_version", strconv.FormatInt(query.PublishedVersion, 10))
	values.Set("start_ms", strconv.FormatInt(query.StartMS, 10))
	values.Set("end_ms", strconv.FormatInt(query.EndMS, 10))
	if query.RegionID > 0 {
		values.Set("region_id", strconv.FormatInt(query.RegionID, 10))
	}
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.baseURL+"/internal/v1/statistics/activity-templates/data?"+values.Encode(), nil)
	if err != nil {
		return ActivityTemplateData{}, err
	}
	resp, err := c.client.Do(req)
	if err != nil {
		return ActivityTemplateData{}, err
	}
	defer resp.Body.Close()
	if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
		var body struct {
			Error string `json:"error"`
		}
		_ = json.NewDecoder(resp.Body).Decode(&body)
		return ActivityTemplateData{}, fmt.Errorf("statistics service returned status %d: %s", resp.StatusCode, strings.TrimSpace(body.Error))
	}
	var out ActivityTemplateData
	if err := json.NewDecoder(resp.Body).Decode(&out); err != nil {
		return ActivityTemplateData{}, err
	}
	// Arrays must remain arrays for dense table/chart clients; nil would serialize as null and force needless branches.
	if out.Trend == nil {
		out.Trend = []ActivityTemplateTrendPoint{}
	}
	if out.Gifts == nil {
		out.Gifts = []ActivityTemplateGiftStat{}
	}
	if out.Tasks == nil {
		out.Tasks = []ActivityTemplateTaskStat{}
	}
	return out, nil
}
