package model

import "time"

// 账户类别取值。
const (
	AccountTypePaid    = "paid"
	AccountTypeTrial   = "trial"
	AccountTypeFree    = "free"
	AccountTypeUnknown = "unknown"
)

// 测活状态取值;suspended 来自账户能力接口的云端暂停标记(区别于失联)。
const (
	AliveStatusAlive     = "alive"
	AliveStatusDead      = "dead"
	AliveStatusSuspended = "suspended"
	AliveStatusUnknown   = "unknown"
)

// Setting 是系统级键值配置；敏感值（如 telegram_bot_token）以 AES-GCM 密文存储。
type Setting struct {
	Key       string    `gorm:"primaryKey;size:64" json:"key"`
	Value     string    `gorm:"type:text" json:"value"`
	UpdatedAt time.Time `json:"updatedAt"`
}

// Proxy 是出站代理配置(socks5 / http / https),供租户 SDK 调用按关联走代理;
// 密码 AES-GCM 加密存储,任何响应不回明文。
type Proxy struct {
	ID          uint   `gorm:"primaryKey" json:"id"`
	Name        string `gorm:"uniqueIndex;size:64" json:"name"`
	Type        string `gorm:"size:16" json:"type"`
	Host        string `gorm:"size:256" json:"host"`
	Port        int    `json:"port"`
	Username    string `gorm:"size:128" json:"username"`
	PasswordEnc string `json:"-"`
	// Country / City 为经代理出口实测的地理位置;GeoAt 为最近一次探测时间,nil 表示尚未探测
	Country   string     `gorm:"size:64" json:"country"`
	City      string     `gorm:"size:64" json:"city"`
	GeoAt     *time.Time `json:"geoAt"`
	CreatedAt time.Time  `json:"createdAt"`
	UpdatedAt time.Time  `json:"updatedAt"`
}

// SystemLog 是面板自身的操作审计（区别于 OCI 云端审计事件）；
// 只存方法、路径等元数据，绝不存请求体，避免私钥 / 口令入库。
type SystemLog struct {
	ID         uint   `gorm:"primaryKey" json:"id"`
	Username   string `gorm:"size:64;index" json:"username"`
	Method     string `gorm:"size:8" json:"method"`
	Path       string `gorm:"size:256" json:"path"`
	Status     int    `json:"status"`
	DurationMs int64  `json:"durationMs"`
	ClientIP   string `gorm:"size:64" json:"clientIp"`
	UserAgent  string `gorm:"size:256" json:"userAgent"`
	// ErrMsg 仅失败请求(>=400)存响应的 error 文案,便于免翻服务端日志定位原因
	ErrMsg    string    `gorm:"size:256" json:"errMsg"`
	CreatedAt time.Time `gorm:"index" json:"createdAt"`
}

// User 是可登录面板的账号，密码只存 bcrypt 哈希。
type User struct {
	ID           uint   `gorm:"primaryKey" json:"id"`
	Username     string `gorm:"uniqueIndex;size:64" json:"username"`
	PasswordHash string `json:"-"`
	// TOTP 共享密钥 AES-GCM 密文;空串表示未启用两步验证
	TotpSecretEnc string `json:"-"`
	// TokenVersion 是 JWT 版本号:凭据/TOTP/外部身份/登录策略变更或撤销会话时
	// 原子递增,旧版本令牌随即失效(存量令牌无 ver 视为 0,与零值兼容)
	TokenVersion uint      `json:"-"`
	CreatedAt    time.Time `json:"createdAt"`
	UpdatedAt    time.Time `json:"updatedAt"`
}

// UserIdentity 是管理员绑定的外部登录身份(OIDC / GitHub);
// 绑定动作只发生在已登录会话内,未绑定的外部身份一律拒绝登录。
type UserIdentity struct {
	ID       uint   `gorm:"primaryKey" json:"id"`
	UserID   uint   `gorm:"index" json:"-"`
	Provider string `gorm:"size:16;uniqueIndex:idx_identity_provider_subject" json:"provider"`
	// OIDC sub / GitHub 数字 id;不回给前端
	Subject string `gorm:"size:255;uniqueIndex:idx_identity_provider_subject" json:"-"`
	// 展示名:邮箱 / GitHub login
	Display   string    `gorm:"size:255" json:"display"`
	CreatedAt time.Time `json:"createdAt"`
}

// 任务类型取值。
const (
	TaskTypeHealthCheck = "health_check" // 定时测活
	TaskTypeSnatch      = "snatch"       // 抢机：反复尝试创建实例直到成功
	TaskTypeCost        = "cost"         // 每日成本同步：拉 Usage API 写本地快照
	TaskTypeAiProbe     = "ai_probe"     // AI 渠道周期探测:随渠道数量自动创建/激活/暂停
)

// 任务状态取值。
const (
	TaskStatusActive    = "active"    // 按 cron 调度中
	TaskStatusPaused    = "paused"    // 手动暂停
	TaskStatusSucceeded = "succeeded" // 抢机成功后自动停止
	TaskStatusFailed    = "failed"    // 熔断停止（如抢机连续鉴权失败）
)

// Task 是一个按 cron 表达式周期执行的后台任务。
// Payload 按任务类型存 JSON：测活为 {"ociConfigIds":[...]}（空为全部），
// 抢机为 {"ociConfigId":1,"instance":{...},"count":1}。
type Task struct {
	ID        uint       `gorm:"primaryKey" json:"id"`
	Name      string     `gorm:"size:128" json:"name"`
	Type      string     `gorm:"size:32;index" json:"type"`
	CronExpr  string     `gorm:"size:64" json:"cronExpr"`
	Payload   string     `gorm:"type:text" json:"payload"`
	Status    string     `gorm:"size:16;index" json:"status"`
	LastRunAt *time.Time `json:"lastRunAt"`
	LastError string     `gorm:"type:text" json:"lastError"`
	RunCount  int        `json:"runCount"`
	CreatedAt time.Time  `json:"createdAt"`
	UpdatedAt time.Time  `json:"updatedAt"`
}

// TaskLog 是任务的一次执行记录。
type TaskLog struct {
	ID         uint      `gorm:"primaryKey" json:"id"`
	TaskID     uint      `gorm:"index" json:"taskId"`
	Success    bool      `json:"success"`
	Message    string    `gorm:"type:text" json:"message"`
	DurationMs int64     `json:"durationMs"`
	CreatedAt  time.Time `json:"createdAt"`
}

// CheckSnapshot 是测活任务为每个配置留下的最新资源快照（每配置一行，覆盖更新）。
// InstanceCount 只统计配置默认区域，用于总览 KPI 与覆盖度标注。
type CheckSnapshot struct {
	ID            uint      `gorm:"primaryKey" json:"id"`
	OciConfigID   uint      `gorm:"uniqueIndex" json:"ociConfigId"`
	AliveStatus   string    `gorm:"size:16" json:"aliveStatus"`
	InstanceCount int       `json:"instanceCount"`
	CheckedAt     time.Time `json:"checkedAt"`
}

// CostSnapshot 是成本任务写入的每配置每日成本（UTC 日界，重复同步覆盖更新）。
type CostSnapshot struct {
	ID          uint      `gorm:"primaryKey" json:"id"`
	OciConfigID uint      `gorm:"uniqueIndex:idx_cost_cfg_day" json:"ociConfigId"`
	Day         string    `gorm:"size:10;uniqueIndex:idx_cost_cfg_day" json:"day"`
	Amount      float64   `json:"amount"`
	Currency    string    `gorm:"size:8" json:"currency"`
	SyncedAt    time.Time `json:"syncedAt"`
}

// OciConfig 保存一份 OCI API Key 配置及其最近一次云端快照。
// 私钥和口令只以 AES-GCM 密文落库，且不出现在 JSON 响应中。
type OciConfig struct {
	ID    uint   `gorm:"primaryKey" json:"id"`
	Alias string `gorm:"uniqueIndex;size:64" json:"alias"`
	// Group 是面板内的自定义分组标签，空串表示未分组；
	// 列名避开 SQL 保留字 GROUP
	Group string `gorm:"column:group_name;size:64;index" json:"group"`

	// ProxyID 关联出站代理,nil 表示直连;该租户全部 SDK 调用经此代理
	ProxyID *uint `gorm:"index" json:"proxyId"`

	UserOCID    string `json:"userOcid"`
	TenancyOCID string `json:"tenancyOcid"`
	Fingerprint string `json:"fingerprint"`
	Region      string `json:"region"`

	// 私钥 PEM 密文约 4KB,必须 text;passphrase 密文同档处理
	PrivateKeyEnc string `gorm:"type:text" json:"-"`
	PassphraseEnc string `gorm:"type:text" json:"-"`

	TenancyName   string `json:"tenancyName"`
	HomeRegionKey string `json:"homeRegionKey"`

	AccountType      string     `json:"accountType"`
	SubscriptionID   string     `json:"subscriptionId"`
	PaymentModel     string     `json:"paymentModel"`
	SubscriptionTier string     `json:"subscriptionTier"`
	PromotionStatus  string     `json:"promotionStatus"`
	PromotionAmount  float32    `json:"promotionAmount"`
	PromotionExpires *time.Time `json:"promotionExpires"`

	AliveStatus    string     `json:"aliveStatus"`
	LastError      string     `gorm:"type:text" json:"lastError"`
	LastVerifiedAt *time.Time `json:"lastVerifiedAt"`

	// 多区域 / 多区间支持：开启后订阅区域与 compartment 列表入库缓存，
	// 供筛选器免实时调 OCI；未开启的租户筛选器锁定主区域 / 根区间。
	MultiRegion      bool `json:"multiRegion"`
	MultiCompartment bool `json:"multiCompartment"`

	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
}

// LogEvent 是 OCI 日志回传事件(方案A:Connector Hub → Notifications → HTTPS 订阅);
// Payload 存 ONS 消息原文(链路单条 ≤128KB,面板另设 256KB 防御上限,超限截断并标记)。
type LogEvent struct {
	ID          uint       `gorm:"primaryKey" json:"id"`
	OciConfigID uint       `gorm:"index" json:"ociConfigId"`              // 经 secret 反查归属租户
	MessageID   string     `gorm:"uniqueIndex;size:128" json:"messageId"` // 幂等键(X-OCI-NS-MessageId)
	EventType   string     `gorm:"size:128;index" json:"eventType"`       // 异步解析回填,如 com.oraclecloud.ComputeApi.TerminateInstance
	Source      string     `gorm:"size:64" json:"source"`
	SourceIP    string     `gorm:"size:64" json:"sourceIp"` // 异步解析回填,Audit 事件的发起方 IP
	EventTime   *time.Time `gorm:"index" json:"eventTime"`
	// 防御上限 256KB 超 MySQL TEXT(64KB),size 上探一档 → MEDIUMTEXT;PG/SQLite 仍为 text
	Payload    string    `gorm:"size:16777216" json:"payload"`
	Truncated  bool      `json:"truncated"`
	Processed  bool      `gorm:"index" json:"processed"`
	ReceivedAt time.Time `json:"receivedAt"`
}

// RegionCache 是开启多区域支持的配置缓存的订阅区域（每配置多行，整组覆盖）。
// Status 非 READY（新订阅进行中）时读取接口会实时刷新，直到全部 READY。
type RegionCache struct {
	ID           uint      `gorm:"primaryKey" json:"-"`
	OciConfigID  uint      `gorm:"index;uniqueIndex:idx_region_cache" json:"-"`
	Key          string    `gorm:"size:8;uniqueIndex:idx_region_cache" json:"key"`
	Name         string    `gorm:"size:64" json:"name"`
	Status       string    `gorm:"size:16" json:"status"`
	IsHomeRegion bool      `json:"isHomeRegion"`
	UpdatedAt    time.Time `json:"updatedAt"`
}

// CompartmentCache 是开启多区间支持的配置缓存的 compartment（每配置多行，整组覆盖）。
type CompartmentCache struct {
	ID          uint      `gorm:"primaryKey" json:"-"`
	OciConfigID uint      `gorm:"index;uniqueIndex:idx_comp_cache" json:"-"`
	OCID        string    `gorm:"size:128;uniqueIndex:idx_comp_cache" json:"id"`
	Name        string    `gorm:"size:128" json:"name"`
	State       string    `gorm:"size:16" json:"lifecycleState"`
	UpdatedAt   time.Time `json:"updatedAt"`
}

// AiKey 是 AI 网关的访问密钥;明文不落库,仅存 SHA-256 与尾 4 位。
// Group 非空时该密钥只在同分组渠道内负载均衡(列名避开 SQL 保留字 group)。
type AiKey struct {
	ID      uint   `gorm:"primaryKey" json:"id"`
	Name    string `gorm:"uniqueIndex;size:64" json:"name"`
	KeyHash string `gorm:"uniqueIndex;size:64" json:"-"`
	Tail    string `gorm:"size:4" json:"tail"`
	Group   string `gorm:"column:key_group;size:32" json:"group"`
	// Models 是模型白名单(精确匹配模型名);空 = 不限,非空时网关仅放行列表内模型
	Models     []string   `gorm:"serializer:json;type:text" json:"models"`
	Enabled    bool       `json:"enabled"`
	LastUsedAt *time.Time `json:"lastUsedAt"`
	// ContentLogUntil 是内容日志开启截止时间;nil = 永关(默认,红线),
	// 开启必须限时,到期自动停写
	ContentLogUntil *time.Time `json:"contentLogUntil"`
	CreatedAt       time.Time  `json:"createdAt"`
}

// AiChannel 是号池渠道 = 租户配置 × 区域;Priority 数字小优先级高,组内按 Weight 加权随机。
// Group 是分组名(列名避开 SQL 保留字 group),空串归属默认分组。
type AiChannel struct {
	ID          uint   `gorm:"primaryKey" json:"id"`
	Name        string `gorm:"size:96" json:"name"`
	OciConfigID uint   `gorm:"uniqueIndex:idx_ai_channel" json:"ociConfigId"`
	Region      string `gorm:"size:32;uniqueIndex:idx_ai_channel" json:"region"`
	Group       string `gorm:"column:channel_group;size:32;index" json:"group"`
	Enabled     bool   `json:"enabled"`
	Priority    int    `json:"priority"`
	Weight      int    `json:"weight"`
	// FailCount 连续失败计数;达阈值后 DisabledUntil 指数退避熔断,成功/探测通过复位
	FailCount     int        `json:"failCount"`
	DisabledUntil *time.Time `json:"disabledUntil"`
	LastProbeAt   *time.Time `json:"lastProbeAt"`
	ProbeStatus   string     `gorm:"size:16" json:"probeStatus"` // ok / no_service / no_quota / error
	ProbeError    string     `gorm:"size:512" json:"probeError"`
	// ProbeModel 是用户测试通过后固定的探测验证模型名;探测时置于候选首位
	ProbeModel string    `gorm:"size:96" json:"probeModel"`
	CreatedAt  time.Time `json:"createdAt"`
	UpdatedAt  time.Time `json:"updatedAt"`
	// ModelCount 是渠道模型缓存计数,列表查询回填,不落库
	ModelCount int64 `gorm:"-" json:"modelCount"`
}

// AiModelCache 是渠道区域的可用模型缓存(整渠道覆盖式同步)。
// Capability 为 CHAT / EMBEDDING / RERANK / TTS;存量空串视为 CHAT(加列前只同步对话模型)。
type AiModelCache struct {
	ID         uint      `gorm:"primaryKey" json:"-"`
	ChannelID  uint      `gorm:"index" json:"channelId"`
	ModelOcid  string    `gorm:"size:160" json:"modelOcid"`
	Name       string    `gorm:"size:96;index" json:"name"`
	Vendor     string    `gorm:"size:32" json:"vendor"`
	Capability string    `gorm:"size:16" json:"capability"`
	SyncedAt   time.Time `json:"syncedAt"`
	// DeprecatedAt 是 OCI 宣布的模型弃用时间;nil 表示未宣布。
	// 弃用后仍可调用,直到 RetiredAt(按需推理退役,同步层已剔除过期项)。
	DeprecatedAt *time.Time `json:"deprecatedAt"`
	RetiredAt    *time.Time `json:"retiredAt"`
}

// AiModelBlacklist 是全局模型黑名单(按模型名):加入即从全部渠道缓存删除该模型,
// 同步与探测过滤不再入库;适用于微调基座等实际不可按需调用的模型,由用户手动维护。
type AiModelBlacklist struct {
	ID        uint      `gorm:"primaryKey" json:"id"`
	Name      string    `gorm:"size:96;uniqueIndex" json:"name"`
	CreatedAt time.Time `json:"createdAt"`
}

// AiCallLog 是网关调用日志:仅元数据与 token 用量,绝不记录 prompt / 响应正文。
type AiCallLog struct {
	ID          uint   `gorm:"primaryKey" json:"id"`
	KeyID       uint   `json:"keyId"`
	KeyName     string `gorm:"size:64" json:"keyName"`
	Endpoint    string `gorm:"size:16" json:"endpoint"` // openai / anthropic
	Model       string `gorm:"size:96" json:"model"`
	ChannelID   uint   `json:"channelId"`
	ChannelName string `gorm:"size:96" json:"channelName"`
	Stream      bool   `json:"stream"`
	Status      int    `json:"status"`
	// ClientIP 是网关调用方来源 IP(尊重「真实 IP 头」安全设置,与系统日志同源)
	ClientIP         string `gorm:"size:64" json:"clientIp"`
	PromptTokens     int    `json:"promptTokens"`
	CompletionTokens int    `json:"completionTokens"`
	TotalTokens      int    `json:"totalTokens"`
	// CachedTokens 是输入中缓存命中(读取)的部分;OCI 隐式缓存无写入计数
	CachedTokens int       `json:"cachedTokens"`
	LatencyMs    int64     `json:"latencyMs"`
	Retries      int       `json:"retries"`
	ErrMsg       string    `gorm:"size:512" json:"errMsg"`
	CreatedAt    time.Time `gorm:"index" json:"createdAt"`
}

// AiContentLog 是网关调用正文抽样——「不落正文」红线的唯一显式例外:
// 仅当调用密钥显式开启内容日志且未过期时写入,到期自动停写;
// 请求正文与非流式响应正文各截断至 64KB,流式响应不记录;保留 7 天 / 1 万行。
type AiContentLog struct {
	ID uint `gorm:"primaryKey" json:"id"`
	// CallLogID 关联同次调用的 AiCallLog,调用日志详情据此反查正文
	CallLogID uint   `gorm:"index" json:"callLogId"`
	KeyID     uint   `gorm:"index" json:"keyId"`
	KeyName   string `gorm:"size:64" json:"keyName"`
	Endpoint  string `gorm:"size:16" json:"endpoint"`
	Model     string `gorm:"size:96" json:"model"`
	Stream    bool   `json:"stream"`
	// RequestBody / ResponseBody 是截断后的正文 JSON;
	// 64KB 截断恰在 MySQL TEXT 上限(65535B)边界,size 上探一档 → MEDIUMTEXT
	RequestBody  string    `gorm:"size:16777216" json:"requestBody"`
	ResponseBody string    `gorm:"size:16777216" json:"responseBody"`
	CreatedAt    time.Time `gorm:"index" json:"createdAt"`
}
