package schema

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

	"aijianzhan/platform/internal/blueprint"
)

// BuildPostgresAlterDDL 对比蓝图与已有表，生成 ADD COLUMN IF NOT EXISTS（Z11a）。
// db 可为 nil：则只返回空（调用方应先 CREATE TABLE）。
func BuildPostgresAlterDDL(ctx context.Context, db *sql.DB, bp *blueprint.Blueprint) ([]string, error) {
	if bp == nil || bp.Storage.SchemaName == "" {
		return nil, fmt.Errorf("schema_name empty")
	}
	if db == nil {
		return nil, nil
	}
	schemaName := bp.Storage.SchemaName
	var stmts []string
	for _, e := range bp.Entities {
		existing, err := listTableColumns(ctx, db, schemaName, e.Table)
		if err != nil {
			return nil, err
		}
		if existing == nil {
			// 表尚不存在：由 CREATE TABLE IF NOT EXISTS 处理
			continue
		}
		for _, f := range e.Fields {
			if _, ok := existing[f.Name]; ok {
				continue
			}
			sqlType, err := mapType(f)
			if err != nil {
				return nil, err
			}
			// 存量表补列一律可空，避免非空约束导致迁库失败
			stmts = append(stmts, fmt.Sprintf(
				`ALTER TABLE %s.%s ADD COLUMN IF NOT EXISTS %s %s`,
				quoteIdent(schemaName), quoteIdent(e.Table), quoteIdent(f.Name), sqlType,
			))
		}
	}
	return stmts, nil
}

func listTableColumns(ctx context.Context, db *sql.DB, schemaName, table string) (map[string]struct{}, error) {
	const q = `
SELECT column_name FROM information_schema.columns
WHERE table_schema = $1 AND table_name = $2`
	rows, err := db.QueryContext(ctx, q, schemaName, table)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	out := map[string]struct{}{}
	found := false
	for rows.Next() {
		found = true
		var name string
		if err := rows.Scan(&name); err != nil {
			return nil, err
		}
		out[name] = struct{}{}
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	if !found {
		return nil, nil
	}
	return out, nil
}

// MergeDDL 将 alter 语句追加到 create ddl 之后。
func MergeDDL(create, alter []string) []string {
	if len(alter) == 0 {
		return create
	}
	out := make([]string, 0, len(create)+len(alter))
	out = append(out, create...)
	out = append(out, alter...)
	return out
}

// Quote for tests
func normalizeSchemaTable(s string) string {
	return strings.TrimSpace(s)
}
