package oci

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

	"github.com/oracle/oci-go-sdk/v65/common"

	"oci-portal/internal/model"
)

// AccountProfile 是一次云端订阅查询得到的账户信息快照。
type AccountProfile struct {
	AccountType      string
	SubscriptionID   string
	ServiceName      string
	PaymentModel     string
	SubscriptionTier string
	PromotionStatus  string
	PromotionAmount  float32
	PromotionExpires *time.Time
}

// AccountCapabilities 是账户能力接口的关键字段。来源为 Limits 服务
// 20230301 版 `/compartments/{tenancy}/capabilities?accountInfoOnly=true`
// (与控制台同源;oci-go-sdk v65 未收录,自签名裸调)。
// 该接口对暂停/已终止租户仍可访问,借此把「暂停」从「失联」中区分出来。
type AccountCapabilities struct {
	Suspended           bool   `json:"suspended"`
	AccountStatus       string `json:"accountStatus"`
	FreeTierEnabled     bool   `json:"freeTierEnabled"`
	FreeTierOnly        bool   `json:"freeTierOnly"`
	PromotionStatus     string `json:"promotionStatus"`
	ProgramType         string `json:"programType"`
	HasSaasSubscription bool   `json:"hasSaasSubscription"`
	Deletable           bool   `json:"deletable"`
}

// capabilitiesEnvelope 对应接口原始响应:顶层与 accountInfo 各有一个
// suspended,任一为 true 即视为暂停。
type capabilitiesEnvelope struct {
	Capabilities struct {
		Suspended   bool `json:"suspended"`
		AccountInfo struct {
			FreeTierEnabled     bool   `json:"freeTierEnabled"`
			FreeTierOnly        bool   `json:"freeTierOnly"`
			PromotionStatus     string `json:"promotionStatus"`
			Suspended           bool   `json:"suspended"`
			ProgramType         string `json:"programType"`
			HasSaasSubscription bool   `json:"hasSaasSubscription"`
			AccountStatus       string `json:"accountStatus"`
			Deletable           bool   `json:"deletable"`
		} `json:"accountInfo"`
	} `json:"capabilities"`
}

// parseAccountCapabilities 把原始响应体压平为关键字段视图。
func parseAccountCapabilities(body []byte) (AccountCapabilities, error) {
	var env capabilitiesEnvelope
	if err := json.Unmarshal(body, &env); err != nil {
		return AccountCapabilities{}, fmt.Errorf("decode account capabilities: %w", err)
	}
	info := env.Capabilities.AccountInfo
	return AccountCapabilities{
		Suspended:           env.Capabilities.Suspended || info.Suspended,
		AccountStatus:       info.AccountStatus,
		FreeTierEnabled:     info.FreeTierEnabled,
		FreeTierOnly:        info.FreeTierOnly,
		PromotionStatus:     info.PromotionStatus,
		ProgramType:         info.ProgramType,
		HasSaasSubscription: info.HasSaasSubscription,
		Deletable:           info.Deletable,
	}, nil
}

// GetAccountCapabilities 实现 Client:查询账户能力(暂停/账户状态/免费层)。
// region 应传 home region;请求带 API Key 签名,并沿用租户出站代理。
func (c *RealClient) GetAccountCapabilities(ctx context.Context, cred Credentials, region string) (AccountCapabilities, error) {
	url := fmt.Sprintf("https://limits.%s.oci.oraclecloud.com/20230301/compartments/%s/capabilities?accountInfoOnly=true",
		normalizeRegion(region), cred.TenancyOCID)
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
	if err != nil {
		return AccountCapabilities{}, fmt.Errorf("new capabilities request: %w", err)
	}
	if err := common.DefaultRequestSigner(provider(cred)).Sign(req); err != nil {
		return AccountCapabilities{}, fmt.Errorf("sign capabilities request: %w", err)
	}
	hc := proxyHTTPClient(cred.Proxy)
	if hc == nil {
		hc = &http.Client{Timeout: proxyClientTimeout}
	}
	resp, err := hc.Do(req)
	if err != nil {
		return AccountCapabilities{}, fmt.Errorf("get account capabilities: %w", err)
	}
	defer resp.Body.Close()
	body, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
	if err != nil {
		return AccountCapabilities{}, fmt.Errorf("read account capabilities: %w", err)
	}
	if resp.StatusCode != http.StatusOK {
		return AccountCapabilities{}, fmt.Errorf("get account capabilities: status %d", resp.StatusCode)
	}
	return parseAccountCapabilities(body)
}

// ClassifyAccount 按订阅字段判定账户类别：
//   - paymentModel 非空且不是 FREE_TRIAL：付费；
//   - paymentModel 为 FREE_TRIAL 时，promotion ACTIVE 或 tier FREE_AND_TRIAL
//     判为试用；promotion EXPIRED 或 tier FREE 判为免费（试用权益已结束）；
//   - 其余情况无法判定。
func ClassifyAccount(paymentModel, subscriptionTier, promotionStatus string) string {
	pm := strings.ToUpper(strings.TrimSpace(paymentModel))
	tier := strings.ToUpper(strings.TrimSpace(subscriptionTier))
	promo := strings.ToUpper(strings.TrimSpace(promotionStatus))
	if pm != "" && pm != "FREE_TRIAL" {
		return model.AccountTypePaid
	}
	if pm == "FREE_TRIAL" {
		switch {
		case promo == "ACTIVE" || tier == "FREE_AND_TRIAL":
			return model.AccountTypeTrial
		case promo == "EXPIRED" || tier == "FREE":
			return model.AccountTypeFree
		}
	}
	return model.AccountTypeUnknown
}
