// Package dbsync：跨库实时同步中间件（SQLite / MySQL / Postgres）。
// 变更写入各端 _ajz_sync_outbox，由 worker 轮询投递；冲突进入队列。
package dbsync

import "time"

const OutboxTable = "_ajz_sync_outbox"
const MetaTable = "_ajz_sync_meta"

type Driver string

const (
	DriverSQLite   Driver = "sqlite"
	DriverMySQL    Driver = "mysql"
	DriverPostgres Driver = "postgres"
)

type Direction string

const (
	DirLocalToRemote  Direction = "local_to_remote"
	DirRemoteToLocal  Direction = "remote_to_local"
	DirBidirectional  Direction = "bidirectional"
)

type ConflictPolicy string

const (
	PolicyQueue     ConflictPolicy = "queue"      // 入冲突队列，人工处理
	PolicyLWWSource ConflictPolicy = "lww_source" // 以源端为准覆盖
	PolicyLWWTarget ConflictPolicy = "lww_target" // 保留目标端，丢弃源变更
)

type Endpoint struct {
	Driver Driver   `json:"driver"` // sqlite | mysql | postgres
	DSN    string   `json:"dsn"`    // 连接串；后台可改线上地址
	Tables []string `json:"tables"` // 要同步的表名
}

type Channel struct {
	ID             string            `json:"id"`
	TenantID       int64             `json:"tenant_id"` // 公司/租户隔离；仅该公司顶级权限可配
	Name           string            `json:"name"`
	Enabled        bool              `json:"enabled"`
	Direction      Direction         `json:"direction"`
	ConflictPolicy ConflictPolicy    `json:"conflict_policy"`
	PollIntervalMS int               `json:"poll_interval_ms"`
	Local          Endpoint          `json:"local"`
	Remote         Endpoint          `json:"remote"`
	PKColumns      map[string]string `json:"pk_columns"` // table -> pk col，默认 id
	// AgentID / AppSlug：把通道挂到某个智能体及其模块，便于「模块数据进该智能体库」对照。
	AgentID   int64  `json:"agent_id,omitempty"`
	AppSlug   string `json:"app_slug,omitempty"`
	// IsSystemDefault：公司默认同步通道（Z12）；表白名单可空（Z4 整库 push）
	IsSystemDefault bool `json:"is_system_default,omitempty"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
	LastError      string         `json:"last_error,omitempty"`
	LastSyncAt     *time.Time     `json:"last_sync_at,omitempty"`
	LastReconcileAt *time.Time    `json:"last_reconcile_at,omitempty"`
	Stats          ChannelStats   `json:"stats"`
}

type ChannelStats struct {
	PushedOK       int64 `json:"pushed_ok"`                 // 兼容：成功 apply 次数
	PushedApplied  int64 `json:"pushed_applied,omitempty"`  // agent/drain 实际写入
	PushedSkipped  int64 `json:"pushed_skipped,omitempty"`  // 同 version 幂等跳过
	PulledOK       int64 `json:"pulled_ok"`
	Conflicts      int64 `json:"conflicts"`
	Retries        int64 `json:"retries"`
	LastBatch      int   `json:"last_batch"`
}

type Conflict struct {
	ID         string    `json:"id"`
	TenantID   int64     `json:"tenant_id"`
	ChannelID  string    `json:"channel_id"`
	Table      string    `json:"table"`
	RowPK      string    `json:"row_pk"`
	Op         string    `json:"op"`
	Source     string    `json:"source"` // local | remote
	Payload    string    `json:"payload"`
	TargetVer  int64     `json:"target_ver"`
	SourceVer  int64     `json:"source_ver"`
	Message    string    `json:"message"`
	CreatedAt  time.Time `json:"created_at"`
	Resolved   bool      `json:"resolved"`
	Resolution string    `json:"resolution,omitempty"` // apply_source | keep_target | discard
}

// LwwOverride LWW 自动覆盖审计（仅平台超级管理员可见；与租户冲突队列分离）。
type LwwOverride struct {
	ID            string    `json:"id"`
	TenantID      int64     `json:"tenant_id"`
	ChannelID     string    `json:"channel_id"`
	Table         string    `json:"table"`
	RowPK         string    `json:"row_pk"`
	Op            string    `json:"op"`
	Entry         string    `json:"entry"`          // drain | agent_push
	Policy        string    `json:"policy"`         // lww_source | lww_target
	Outcome       string    `json:"outcome"`        // applied_source | kept_target
	LoserPayload  string    `json:"loser_payload"`  // 落败侧
	WinnerPayload string    `json:"winner_payload"` // 胜出侧
	TargetVer     int64     `json:"target_ver"`
	SourceVer     int64     `json:"source_ver"`
	CreatedAt     time.Time `json:"created_at"`
}

type OutboxRow struct {
	ID        int64
	TableName string
	RowPK     string
	Op        string // upsert | delete
	Payload   string
	Version   int64
	CreatedAt time.Time
}

type TestResult struct {
	OK      bool     `json:"ok"`
	Driver  string   `json:"driver"`
	Message string   `json:"message"`
	Tables  []string `json:"tables,omitempty"`
}
