package dbsync

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

// EnsureTableFromRow 表不存在时按行字段自动建表（TEXT 列 + PK），满足 Z4「按 Binding 接受任意表」。
func EnsureTableFromRow(ctx context.Context, db *sql.DB, driver Driver, table, pkCol string, row map[string]any) error {
	table = strings.TrimSpace(table)
	pkCol = strings.TrimSpace(pkCol)
	if table == "" || pkCol == "" {
		return fmt.Errorf("table and pk required")
	}
	if row == nil {
		row = map[string]any{pkCol: ""}
	}
	cols := make([]string, 0, len(row))
	seen := map[string]struct{}{}
	if _, ok := row[pkCol]; !ok {
		cols = append(cols, pkCol)
		seen[pkCol] = struct{}{}
	}
	for k := range row {
		k = strings.TrimSpace(k)
		if k == "" {
			continue
		}
		if _, ok := seen[k]; ok {
			continue
		}
		seen[k] = struct{}{}
		cols = append(cols, k)
	}
	return EnsureTableFromColumns(ctx, db, driver, table, pkCol, cols)
}

// EnsureTableFromColumns 按列名建空表（全部 TEXT，指定 PK）。
// 已存在时补齐缺失列（ADD COLUMN），解决「先按 _row_id 建表、后 push 注入 id」导致的缺列 503。
func EnsureTableFromColumns(ctx context.Context, db *sql.DB, driver Driver, table, pkCol string, columns []string) error {
	table = strings.TrimSpace(table)
	pkCol = strings.TrimSpace(pkCol)
	if table == "" {
		return fmt.Errorf("table required")
	}
	if strings.HasPrefix(table, "_ajz_") {
		return fmt.Errorf("sync system table not allowed: %s", table)
	}
	if pkCol == "" {
		pkCol = "id"
	}
	exists, err := tableExists(ctx, db, driver, table)
	if err != nil {
		return err
	}
	want := make([]string, 0, len(columns)+1)
	seen := map[string]struct{}{}
	add := func(c string) {
		c = strings.TrimSpace(c)
		if c == "" {
			return
		}
		if _, ok := seen[c]; ok {
			return
		}
		seen[c] = struct{}{}
		want = append(want, c)
	}
	add(pkCol)
	for _, c := range columns {
		add(c)
	}
	if len(want) == 0 {
		return fmt.Errorf("columns required")
	}
	if exists {
		have, err := listColumns(ctx, db, driver, table)
		if err != nil {
			return err
		}
		haveSet := map[string]struct{}{}
		for _, c := range have {
			haveSet[c] = struct{}{}
		}
		for _, c := range want {
			if _, ok := haveSet[c]; ok {
				continue
			}
			ddl := fmt.Sprintf(`ALTER TABLE %s ADD COLUMN %s TEXT`, quoteIdent(driver, table), quoteIdent(driver, c))
			if _, err := db.ExecContext(ctx, ddl); err != nil {
				// SQLite 无 IF NOT EXISTS；并发下可能已存在
				if !strings.Contains(strings.ToLower(err.Error()), "duplicate column") {
					return err
				}
			}
		}
		return nil
	}
	defs := make([]string, 0, len(want))
	defs = append(defs, fmt.Sprintf("%s TEXT PRIMARY KEY", quoteIdent(driver, pkCol)))
	for _, c := range want {
		if c == pkCol {
			continue
		}
		defs = append(defs, fmt.Sprintf("%s TEXT", quoteIdent(driver, c)))
	}
	ddl := fmt.Sprintf(`CREATE TABLE IF NOT EXISTS %s (%s)`, quoteIdent(driver, table), strings.Join(defs, ", "))
	_, err = db.ExecContext(ctx, ddl)
	return err
}

func tableExists(ctx context.Context, db *sql.DB, driver Driver, table string) (bool, error) {
	var q string
	switch driver {
	case DriverSQLite:
		q = `SELECT 1 FROM sqlite_master WHERE type='table' AND name=? LIMIT 1`
	case DriverMySQL:
		q = `SELECT 1 FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name=? LIMIT 1`
	case DriverPostgres:
		q = `SELECT 1 FROM information_schema.tables WHERE table_schema=current_schema() AND table_name=$1 LIMIT 1`
	default:
		return false, fmt.Errorf("unsupported driver")
	}
	var n int
	err := db.QueryRowContext(ctx, q, table).Scan(&n)
	if err == sql.ErrNoRows {
		return false, nil
	}
	if err != nil {
		return false, err
	}
	return true, nil
}
