package dbsync

import (
	"context"
	"database/sql"
	"fmt"
	"time"
)

const FlagTable = "_ajz_sync_flag"

// EnsureFlagTable：SQLite 用表标记「正在应用远端变更」，避免触发器回声。
func EnsureFlagTable(ctx context.Context, db *sql.DB, driver Driver) error {
	if driver != DriverSQLite {
		return nil
	}
	_, err := db.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS `+FlagTable+` (
  k TEXT PRIMARY KEY,
  v INTEGER NOT NULL DEFAULT 0
);`)
	if err != nil {
		return err
	}
	_, _ = db.ExecContext(ctx, `INSERT OR IGNORE INTO `+FlagTable+`(k,v) VALUES('applying',0)`)
	return nil
}

// WithApplying 在写入目标库时置位，使触发器不写 outbox（防 A↔B 回声导致「多」）。
func WithApplying(ctx context.Context, db *sql.DB, driver Driver, fn func() error) error {
	switch driver {
	case DriverSQLite:
		if err := EnsureFlagTable(ctx, db, driver); err != nil {
			return err
		}
		if _, err := db.ExecContext(ctx, `UPDATE `+FlagTable+` SET v=1 WHERE k='applying'`); err != nil {
			return err
		}
		defer func() {
			_, _ = db.ExecContext(context.Background(), `UPDATE `+FlagTable+` SET v=0 WHERE k='applying'`)
		}()
		return fn()
	case DriverMySQL:
		if _, err := db.ExecContext(ctx, `SET @ajz_applying = 1`); err != nil {
			return err
		}
		defer func() { _, _ = db.ExecContext(context.Background(), `SET @ajz_applying = 0`) }()
		return fn()
	case DriverPostgres:
		if _, err := db.ExecContext(ctx, `SELECT set_config('ajz.applying', '1', false)`); err != nil {
			return err
		}
		defer func() {
			_, _ = db.ExecContext(context.Background(), `SELECT set_config('ajz.applying', '0', false)`)
		}()
		return fn()
	default:
		return fn()
	}
}

func EnqueueOutbox(ctx context.Context, db *sql.DB, driver Driver, table, pk, op, payload string, version int64) error {
	if version <= 0 {
		version = time.Now().UnixMilli()
	}
	switch driver {
	case DriverPostgres:
		_, err := db.ExecContext(ctx, fmt.Sprintf(`
INSERT INTO %s(table_name,row_pk,op,payload,version) VALUES($1,$2,$3,$4,$5)`, OutboxTable),
			table, pk, op, payload, version)
		return err
	default:
		_, err := db.ExecContext(ctx, fmt.Sprintf(`
INSERT INTO %s(table_name,row_pk,op,payload,version) VALUES(?,?,?,?,?)`, OutboxTable),
			table, pk, op, payload, version)
		return err
	}
}
