package base

import (
	_ "blazing/modules/base/packed"
	"context"
	"fmt"

	"blazing/cool"

	_ "blazing/modules/base/controller"
	_ "blazing/modules/base/funcs"
	_ "blazing/modules/base/middleware"
	"blazing/modules/base/model"

	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gctx"
	"github.com/gogf/gf/v2/util/gconv"
)

// trueVal: 条件为 true 时返回的值
// falseVal: 条件为 false 时返回的值
// 返回值类型与 trueVal、falseVal 一致（需保证两者类型相同）
func If[T any](condition bool, trueVal, falseVal T) T {
	if condition {
		return trueVal
	}
	return falseVal
}

func init() {
	var (
		ctx = gctx.GetInitCtx()
	)
	cool.Loger.Debug(ctx, "module base init start ...")

	var t bool
	cool.FillInitData(ctx, "base", &model.BaseSysMenu{}, &t)

	cool.FillInitData(ctx, "base", &model.BaseSysUser{}, &t)
	cool.FillInitData(ctx, "base", &model.BaseSysUserRole{}, &t)
	cool.FillInitData(ctx, "base", &model.BaseSysRole{}, &t)
	cool.FillInitData(ctx, "base", &model.BaseSysRoleMenu{}, &t)
	cool.FillInitData(ctx, "base", &model.BaseSysDepartment{}, &t)
	cool.FillInitData(ctx, "base", &model.BaseSysRoleDepartment{}, &t)
	cool.FillInitData(ctx, "base", &model.BaseSysParam{}, &t)
	cool.FillInitData(ctx, "base", &model.BaseSysConf{}, &t)
	if t {
		ResetAllSequences(ctx)
	}

	// 	g.DB("default").Exec(context.Background(), `CREATE OR REPLACE FUNCTION reset_all_sequences()
	// RETURNS void AS $$
	// DECLARE
	//   seq_record record;
	// BEGIN
	//   FOR seq_record IN
	//     SELECT
	//       'SELECT SETVAL(' ||
	//       quote_literal(quote_ident(PGT.schemaname) || '.' || quote_ident(S.relname)) ||
	//       ', COALESCE(MAX(' ||quote_ident(C.attname)|| '), 1) ) FROM ' ||
	//       quote_ident(PGT.schemaname)|| '.'||quote_ident(T.relname)|| ';' AS sql
	//     FROM
	//       pg_class AS S,
	//       pg_depend AS D,
	//       pg_class AS T,
	//       pg_attribute AS C,
	//       pg_tables AS PGT
	//     WHERE
	//       S.relkind = 'S'
	//       AND S.oid = D.objid
	//       AND D.refobjid = T.oid
	//       AND D.refobjid = C.attrelid
	//       AND D.refobjsubid = C.attnum
	//       AND T.relname = PGT.tablename
	//   LOOP
	//     EXECUTE seq_record.sql;
	//   END LOOP;
	// END;
	// $$ LANGUAGE plpgsql;

	// -- 执行函数
	// SELECT reset_all_sequences();`, nil) //重置所有序列
	cool.Loger.Debug(ctx, "module base init finished ...")

}

func ResetAllSequences(ctx context.Context) error {
	// 查询所有序列及其关联的表和字段信息
	query := `
		SELECT 
			n.nspname AS schema_name,
			s.relname AS sequence_name,
			t.relname AS table_name,
			a.attname AS column_name
		FROM 
			pg_class s
			JOIN pg_depend d ON s.oid = d.objid
			JOIN pg_class t ON d.refobjid = t.oid
			JOIN pg_attribute a ON d.refobjid = a.attrelid AND d.refobjsubid = a.attnum
			JOIN pg_namespace n ON s.relnamespace = n.oid
		WHERE 
			s.relkind = 'S' 
			AND n.nspname NOT IN ('pg_catalog', 'information_schema')
	`

	// 执行查询获取序列信息
	records, err := g.DB("default").Query(ctx, query)
	if err != nil {
		return fmt.Errorf("查询序列信息失败: %w", err)
	}

	// 遍历每个序列并重置
	for _, record := range records {
		schemaName := record.Map()["schema_name"]
		sequenceName := record.Map()["sequence_name"]
		tableName := record.Map()["table_name"]
		columnName := record.Map()["column_name"]

		// 获取表中对应列的最大值
		maxValueQuery := fmt.Sprintf(`SELECT MAX("%s") FROM "%s"."%s"`,
			columnName, schemaName, tableName)

		maxValueRecord, err := g.DB("default").Query(ctx, maxValueQuery)
		if err != nil {
			cool.Loger.Warning(ctx, fmt.Sprintf("获取表 %s.%s 的最大值失败: %v",
				schemaName, tableName, err))
			continue
		}

		// 处理最大值结果
		var maxValue int64 = 1
		if len(maxValueRecord) > 0 && !maxValueRecord[0].IsEmpty() {
			maxValue = gconv.Int64(maxValueRecord[0].Map()["max"])
			if maxValue < 1 {
				maxValue = 1
			}
		}

		// 重置序列值
		resetQuery := fmt.Sprintf(`SELECT SETVAL('%s.%s', %d)`,
			schemaName, sequenceName, maxValue)

		_, err = g.DB("default").Exec(ctx, resetQuery)
		if err != nil {
			cool.Loger.Warning(ctx, fmt.Sprintf("重置序列 %s.%s 失败: %v",
				schemaName, sequenceName, err))
			continue
		}

		cool.Loger.Info(ctx, fmt.Sprintf("序列 %s.%s 已重置为 %d",
			schemaName, sequenceName, maxValue))
	}

	return nil
}
