// Package store 数据模型与迁移。schema 设计见 doc/backend-architecture.html 第六章。
package store

import (
	"time"

	"gorm.io/datatypes"
)

type User struct {
	ID             string `gorm:"primaryKey;size:32"`
	Nickname       string `gorm:"size:64"`
	AvatarURL      string `gorm:"size:512"`
	BalanceSeconds int64  `gorm:"not null;default:0"` // 冗余列，与 balance_ledger 同事务更新
	CreatedAt      time.Time
}

type WechatIdentity struct {
	ID        uint   `gorm:"primaryKey"`
	UserID    string `gorm:"size:32;index;not null"`
	OpenID    string `gorm:"size:64;uniqueIndex;not null"`
	UnionID   string `gorm:"size:64;index"`
	AppType   string `gorm:"size:16;not null"` // web | mobile
	CreatedAt time.Time
}

// EmailIdentity 邮箱验证码登录身份（桌面端第二登录方式）。
type EmailIdentity struct {
	ID        uint   `gorm:"primaryKey"`
	UserID    string `gorm:"size:32;index;not null"`
	Email     string `gorm:"size:255;uniqueIndex;not null"`
	CreatedAt time.Time
}

type DurationPack struct {
	ID         string `gorm:"primaryKey;size:32"`
	Minutes    int    `gorm:"not null"`
	PriceCents int    `gorm:"not null"`
	UnitDesc   string `gorm:"size:64"`
	Tag        string `gorm:"size:32"`
	Sort       int
	Active     bool `gorm:"not null;default:true"`
}

const (
	OrderPending = "pending"
	OrderPaid    = "paid"
	OrderClosed  = "closed"
)

type Order struct {
	ID            string  `gorm:"primaryKey;size:32"`
	UserID        string  `gorm:"size:32;index;not null"`
	PackID        string  `gorm:"size:32;not null"`
	PriceCents    int     `gorm:"not null"`
	Channel       string  `gorm:"size:16;not null"`            // native | app
	Status        string  `gorm:"size:16;not null;index"`      // pending | paid | closed
	TransactionID *string `gorm:"size:64;uniqueIndex"`         // 微信支付单号，幂等去重
	PaidAt        *time.Time
	CreatedAt     time.Time
}

const (
	LedgerPurchase = "purchase"
	LedgerUsage    = "usage"
	LedgerGift     = "gift"
)

// BalanceLedger 时长账本：只追加不修改，余额 = SUM(delta_seconds)。
type BalanceLedger struct {
	ID           uint   `gorm:"primaryKey"`
	UserID       string `gorm:"size:32;index;not null"`
	DeltaSeconds int64  `gorm:"not null"` // + 购买/赠送，− 用量
	Reason       string `gorm:"size:16;not null"`
	OrderID      *string `gorm:"size:32"`
	SessionID    *string `gorm:"size:64"`
	CreatedAt    time.Time
}

// TrialUsage 每日免费试用：自然日（Asia/Shanghai）为键，无记录即未使用。
type TrialUsage struct {
	UserID      string `gorm:"primaryKey;size:32"`
	Date        string `gorm:"primaryKey;size:10"` // YYYY-MM-DD
	UsedSeconds int    `gorm:"not null;default:0"`
}

// ASRSession 识别会话用量明细（计费拆分 + 排障）。
type ASRSession struct {
	ID           string `gorm:"primaryKey;size:64"`
	UserID       string `gorm:"size:32;index;not null"`
	DeviceID     string `gorm:"size:64"`
	AudioSeconds int    `gorm:"not null"`
	TrialPart    int    `gorm:"not null"` // 试用扣减部分
	BalancePart  int    `gorm:"not null"` // 余额扣减部分
	ProviderMs   int64  // Provider 报告的识别时长（ms），与 AudioSeconds 交叉校验/审计
	Provider     string `gorm:"size:16"`
	Canceled     bool
	CreatedAt    time.Time `gorm:"index"`
}

type Device struct {
	ID         string `gorm:"primaryKey;size:64"`
	UserID     string `gorm:"size:32;index"`
	Platform   string `gorm:"size:16"` // mac | win | ios | android
	AppVersion string `gorm:"size:32"`
	LastSeen   time.Time
}

const (
	FeedbackNew      = "new"
	FeedbackTriaged  = "triaged"
	FeedbackResolved = "resolved"
)

// Feedback 用户反馈（v1.1）。
type Feedback struct {
	ID          string         `gorm:"primaryKey;size:32"`
	UserID      string         `gorm:"size:32;index;not null"`
	Content     string         `gorm:"type:text;not null"`
	Images      datatypes.JSON // OSS keys: ["fb/{id}/1.png", ...]
	Diagnostics datatypes.JSON
	Platform    string `gorm:"size:16"`
	AppVersion  string `gorm:"size:32"`
	Status      string `gorm:"size:16;not null;default:new;index"`
	CreatedAt   time.Time
}

// MetricEvent 客户端打点原始事件（v1.1，保留 90 天定期清理）。
type MetricEvent struct {
	ID         uint64  `gorm:"primaryKey"`
	UserID     *string `gorm:"size:32"`
	DeviceID   string  `gorm:"size:64;not null"`
	Platform   string  `gorm:"size:16"`
	AppVersion string  `gorm:"size:32"`
	OSVersion  string  `gorm:"size:64"`
	Event      string  `gorm:"size:64;not null;index"`
	Props      datatypes.JSON
	ClientTs   int64
	ReceivedAt time.Time // BRIN 索引在 Open() 中按 PG 专属 DDL 创建
}

// MetricDaily 每日聚合（event × platform × date）。
type MetricDaily struct {
	Date     string  `gorm:"primaryKey;size:10"`
	Event    string  `gorm:"primaryKey;size:64"`
	Platform string  `gorm:"primaryKey;size:16"`
	Count    int64   `gorm:"not null"`
	P50Ms    float64 `gorm:"not null;default:0"`
	P95Ms    float64 `gorm:"not null;default:0"`
}

// AllModels 迁移清单（12 张表）。
func AllModels() []any {
	return []any{
		&User{}, &WechatIdentity{}, &EmailIdentity{}, &DurationPack{}, &Order{}, &BalanceLedger{},
		&TrialUsage{}, &ASRSession{}, &Device{}, &Feedback{}, &MetricEvent{}, &MetricDaily{},
	}
}
