package migrations

import (
	"ALLinSSL/backend/public"
	"ALLinSSL/backend/public/sqlite_migrate"
	"database/sql"
	"fmt"
	_ "modernc.org/sqlite"
	"os"
	"path/filepath"
)

func init() {
	// 指定运行目录为当前目录
	exePath, err := os.Executable()
	if err != nil {
		fmt.Fprintf(os.Stderr, "获取可执行文件路径失败: %v\n", err)
		os.Exit(1)
	}
	exePath, err = filepath.EvalSymlinks(exePath) // 解决 macOS/Linux 下软链接问题
	if err != nil {
		fmt.Fprintf(os.Stderr, "解析软链接失败: %v\n", err)
		os.Exit(1)
	}
	exeDir := filepath.Dir(exePath)
	err = os.Chdir(exeDir)
	if err != nil {
		fmt.Fprintf(os.Stderr, "切换目录失败: %v\n", err)
		os.Exit(1)
	}

	os.MkdirAll("data", os.ModePerm)

	dbPath := "data/data.db"
	_, _ = filepath.Abs(dbPath)
	// fmt.Println("数据库路径:", absPath)
	db, err := sql.Open("sqlite", dbPath)
	if err != nil {
		// fmt.Println("创建数据库失败:", err)
		return
	}
	defer db.Close()
	// 创建表
	_, err = db.Exec(`
	PRAGMA journal_mode=WAL;
	
	create table IF NOT EXISTS access
	(
	    id          integer not null
	        constraint access_pk
	            primary key autoincrement,
	    config      TEXT    not null,
	    type        TEXT    not null,
	    create_time TEXT,
	    update_time TEXT,
	    name        TEXT    not null
	);
	
	create table IF NOT EXISTS access_type
	(
	    id   integer not null
	        constraint access_type_pk
	            primary key autoincrement,
	    name TEXT,
	    type TEXT
	);
	
	create table IF NOT EXISTS cert
	(
	    id          integer not null
	        constraint cert_pk
	            primary key autoincrement,
	    source      TEXT    not null,
	    sha256      TEXT,
	    history_id  TEXT,
	    key         TEXT    not null,
	    cert        TEXT    not null,
	    issuer_cert integer,
	    domains     TEXT    not null,
	    create_time TEXT,
	    update_time TEXT,
	    issuer      TEXT    not null,
	    start_time  TEXT,
	    end_time    TEXT,
	    end_day     TEXT,
	    workflow_id TEXT
	);
	
	create table IF NOT EXISTS report
	(
	    id          integer not null
	        constraint report_pk
	            primary key autoincrement,
	    type        TEXT    not null,
	    config      TEXT    not null,
	    create_time TEXT,
	    update_time TEXT,
	    name        TEXT
	);
	
	create table IF NOT EXISTS workflow
	(
	    id              integer not null
	        constraint workflow_pk
	            primary key autoincrement,
	    name            TEXT    not null,
	    content         TEXT    not null,
	    cron            TEXT,
	    create_time     TEXT,
	    update_time     TEXT,
	    active          integer,
	    exec_type       TEXT,
	    last_run_status TEXT,
	    exec_time       TEXT,
	    last_run_time   TEXT
	);
	
	create table IF NOT EXISTS workflow_history
	(
	    id          TEXT not null
	        constraint work_flow_pk
	            primary key,
	    status      TEXT,
	    exec_type   TEXT,
	    create_time TEXT,
	    end_time    TEXT,
	    workflow_id TEXT not null
	);

	create table IF NOT EXISTS workflow_deploy
	(
		id          TEXT,
		workflow_id TEXT,
		cert_hash   TEXT,
		status      TEXT,
		constraint workflow_deploy_pk
			primary key (id, workflow_id)
	);

	`)
	insertDefaultData(db, "access_type", `
	INSERT INTO access_type (name, type) VALUES ('aliyun', 'dns');
	INSERT INTO access_type (name, type) VALUES ('tencentcloud', 'dns');
	INSERT INTO access_type (name, type) VALUES ('aliyun', 'host');
	INSERT INTO access_type (name, type) VALUES ('tencentcloud', 'host');
	INSERT INTO access_type (name, type) VALUES ('ssh', 'host');
	INSERT INTO access_type (name, type) VALUES ('btpanel', 'host');
	INSERT INTO access_type (name, type) VALUES ('1panel', 'host');`)

	InsertIfNotExists(db, "access_type", map[string]any{"name": "cloudflare", "type": "host"}, []string{"name", "type"}, []any{"cloudflare", "host"})
	InsertIfNotExists(db, "access_type", map[string]any{"name": "cloudflare", "type": "dns"}, []string{"name", "type"}, []any{"cloudflare", "dns"})
	InsertIfNotExists(db, "access_type", map[string]any{"name": "huaweicloud", "type": "host"}, []string{"name", "type"}, []any{"huaweicloud", "host"})
	InsertIfNotExists(db, "access_type", map[string]any{"name": "huaweicloud", "type": "dns"}, []string{"name", "type"}, []any{"huaweicloud", "dns"})

	InsertIfNotExists(db, "access_type", map[string]any{"name": "baidu", "type": "host"}, []string{"name", "type"}, []any{"baidu", "host"})
	InsertIfNotExists(db, "access_type", map[string]any{"name": "baidu", "type": "dns"}, []string{"name", "type"}, []any{"baidu", "dns"})

	InsertIfNotExists(db, "access_type", map[string]any{"name": "btwaf", "type": "host"}, []string{"name", "type"}, []any{"btwaf", "host"})
	InsertIfNotExists(db, "access_type", map[string]any{"name": "doge", "type": "host"}, []string{"name", "type"}, []any{"doge", "host"})
	InsertIfNotExists(db, "access_type", map[string]any{"name": "plugin", "type": "host"}, []string{"name", "type"}, []any{"plugin", "host"})

	// 雷池
	InsertIfNotExists(db, "access_type", map[string]any{"name": "safeline", "type": "host"}, []string{"name", "type"}, []any{"safeline", "host"})
	// 七牛
	InsertIfNotExists(db, "access_type", map[string]any{"name": "qiniu", "type": "host"}, []string{"name", "type"}, []any{"qiniu", "host"})
	// 西部数码
	InsertIfNotExists(db, "access_type", map[string]any{"name": "westcn", "type": "dns"}, []string{"name", "type"}, []any{"westcn", "dns"})
	// 火山引擎
	InsertIfNotExists(db, "access_type", map[string]any{"name": "volcengine", "type": "dns"}, []string{"name", "type"}, []any{"volcengine", "dns"})
	InsertIfNotExists(db, "access_type", map[string]any{"name": "volcengine", "type": "host"}, []string{"name", "type"}, []any{"volcengine", "host"})
	// godaddy
	InsertIfNotExists(db, "access_type", map[string]any{"name": "godaddy", "type": "dns"}, []string{"name", "type"}, []any{"godaddy", "dns"})

	InsertIfNotExists(db, "access_type", map[string]any{"name": "namecheap", "type": "dns"}, []string{"name", "type"}, []any{"namecheap", "dns"})
	InsertIfNotExists(db, "access_type", map[string]any{"name": "ns1", "type": "dns"}, []string{"name", "type"}, []any{"ns1", "dns"})
	InsertIfNotExists(db, "access_type", map[string]any{"name": "cloudns", "type": "dns"}, []string{"name", "type"}, []any{"cloudns", "dns"})
	InsertIfNotExists(db, "access_type", map[string]any{"name": "aws", "type": "dns"}, []string{"name", "type"}, []any{"aws", "dns"})
	InsertIfNotExists(db, "access_type", map[string]any{"name": "azure", "type": "dns"}, []string{"name", "type"}, []any{"azure", "dns"})

	InsertIfNotExists(db, "access_type", map[string]any{"name": "jdcloud", "type": "dns"}, []string{"name", "type"}, []any{"jdcloud", "dns"})
	InsertIfNotExists(db, "access_type", map[string]any{"name": "gcore", "type": "dns"}, []string{"name", "type"}, []any{"gcore", "dns"})
	InsertIfNotExists(db, "access_type", map[string]any{"name": "bunny", "type": "dns"}, []string{"name", "type"}, []any{"bunny", "dns"})
	InsertIfNotExists(db, "access_type", map[string]any{"name": "namedotcom", "type": "dns"}, []string{"name", "type"}, []any{"namedotcom", "dns"})
	InsertIfNotExists(db, "access_type", map[string]any{"name": "namesilo", "type": "dns"}, []string{"name", "type"}, []any{"namesilo", "dns"})
	InsertIfNotExists(db, "access_type", map[string]any{"name": "constellix", "type": "dns"}, []string{"name", "type"}, []any{"constellix", "dns"})
	InsertIfNotExists(db, "access_type", map[string]any{"name": "lecdn", "type": "host"}, []string{"name", "type"}, []any{"lecdn", "host"})

	InsertIfNotExists(db, "access_type", map[string]any{"name": "spaceship", "type": "dns"}, []string{"name", "type"}, []any{"spaceship", "dns"})

	InsertIfNotExists(db, "access_type", map[string]any{"name": "webhook", "type": "dns"}, []string{"name", "type"}, []any{"webhook", "dns"})
	InsertIfNotExists(db, "access_type", map[string]any{"name": "webhook", "type": "host"}, []string{"name", "type"}, []any{"webhook", "host"})

	InsertIfNotExists(db, "access_type", map[string]any{"name": "btdomain", "type": "dns"}, []string{"name", "type"}, []any{"btdomain", "dns"})

	err = sqlite_migrate.EnsureDatabaseWithTables(
		"data/site_monitor.db",
		"data/data.db",
		[]string{"site_monitor"}, // 你要迁移的表
	)
	if err != nil {
		fmt.Println("错误:", err)
	}

	dbSetting, err := sql.Open("sqlite", "data/settings.db")
	if err != nil {
		//fmt.Println("创建 settings 数据库失败:", err)
		return
	}
	defer dbSetting.Close()
	// 创建表
	_, err = dbSetting.Exec(`
	PRAGMA journal_mode=WAL;

	create table IF NOT EXISTS settings
	(
	    id          integer
	        constraint settings_pk
	            primary key,
	    key         TEXT,
	    value       TEXT,
	    create_time TEXT    not null,
	    update_time TEXT    not null,
	    active      integer not null,
	    type        TEXT
	);

	create table IF NOT EXISTS users
	(
	    id       integer         not null
	        constraint users_pk
	            primary key autoincrement,
	    username TEXT            not null
	        constraint users_pk2
	            unique,
	    password TEXT            not null,
	    salt     TEXT default '' not null
	);
       `)
	insertDefaultData(dbSetting, "users", "INSERT INTO users (id, username, password, salt) VALUES (1, 'admin', 'xxxxxxx', '&*ghs^&%dag');")
	uuidStr := public.GenerateUUID()
	randomStr := public.RandomString(8)

	port, err := public.GetFreePort()
	if err != nil {
		port = 20773
	}

	Isql := fmt.Sprintf(
		`INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ('log_path', 'logs/ALLinSSL.log', '2025-04-15 15:58', '2025-04-15 15:58', 1, null);
INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ( 'workflow_log_path', 'logs/workflows/', '2025-04-15 15:58', '2025-04-15 15:58', 1, null);
INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ( 'timeout', '86400', '2025-04-15 15:58', '2025-04-15 15:58', 1, null);
INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ( 'https', '0', '2025-04-15 15:58', '2025-04-15 15:58', 1, null);
INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ('session_key', '%s', '2025-04-15 15:58', '2025-04-15 15:58', 1, null);
INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ('secure', '/%s', '2025-04-15 15:58', '2025-04-15 15:58', 1, null);
INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ('port', '%d', '2025-04-15 15:58', '2025-04-15 15:58', 1, null);`, uuidStr, randomStr, port)

	insertDefaultData(dbSetting, "settings", Isql)
	InsertIfNotExists(dbSetting, "settings", map[string]any{"key": "plugin_dir"}, []string{"key", "value", "create_time", "update_time", "active"}, []any{"plugin_dir", "plugins", "2025-04-15 15:58", "2025-04-15 15:58", 1})

	err = sqlite_migrate.EnsureDatabaseWithTables(
		"data/accounts.db",
		"data/data.db",
		[]string{"_accounts", "_eab"}, // 你要迁移的表
	)
	if err != nil {
		fmt.Println("错误:", err)
	}
	dbAcc, err := sql.Open("sqlite", "data/accounts.db")
	if err != nil {
		//fmt.Println("创建 settings 数据库失败:", err)
		return
	}
	defer dbAcc.Close()
	// 创建表
	_, err = dbAcc.Exec(`
	PRAGMA journal_mode=WAL;

	create table if not exists accounts
	(
		id          integer not null
			constraint _accounts_pk
				primary key autoincrement,
		private_key TEXT    ,
		reg         TEXT    ,
		email       TEXT    not null,
		type        TEXT    not null,
		Kid         TEXT    ,
		HmacEncoded         TEXT    ,
		CADirURL         TEXT    ,
		create_time TEXT,
		update_time TEXT
	);
       `)
	insertSql := `
	insert into accounts (id, private_key, reg, email, create_time, update_time, type, Kid, HmacEncoded)
	select a.id, a.private_key, a.reg, a.email, a.create_time, a.update_time, case when a.type like 'sslcom%' then 'sslcom' else a.type end, b.Kid,b.HmacEncoded
	from _accounts a
	left join _eab b
		on a.email = b.mail and a.type like b.ca||'%';
`
	insertDefaultData(dbAcc, "accounts", insertSql)

	sourceDBPath := "data/site_monitor.db"
	if _, err := os.Stat(sourceDBPath); err != nil {
		sourceDBPath = "data/data.db"
	}

	columnMapping := map[string]string{
		"name":            "name",
		"site_domain":     "target",
		"report_type":     "report_types",
		"active":          "active",
		"last_time":       "last_time",
		"except_end_time": "except_end_time",
		"update_time":     "update_time",
		"create_time":     "create_time",
		"cycle":           "cycle",
		"repeat_send_gap": "repeat_send_gap",
	}

	createTableSQL := `
create table monitor
(
    id              integer                 not null
        constraint monitor_pk
            primary key autoincrement,
    name            TEXT                    not null,
    target          TEXT                    not null,
    monitor_type    TEXT    default 'https' not null,
    report_types    TEXT                    not null,
    active          integer default 1,
    info            TEXT,
    last_time       TEXT,
    except_end_time TEXT,
    update_time     TEXT,
    create_time     TEXT,
    cycle           integer,
    repeat_send_gap integer default 10,
    advance_day     integer default 30,
    valid           INTEGER default 0       not null
);`

	err = sqlite_migrate.MigrateSQLiteTable(
		sourceDBPath,
		"site_monitor",
		"data/monitor.db",
		"monitor",
		columnMapping,
		createTableSQL,
		1000,
	)
	if err != nil {
		//fmt.Println("迁移失败:", err)
		return
	}

	dbMonitor, err := sql.Open("sqlite", "data/monitor.db")
	if err != nil {
		// fmt.Println("创建 monitor 数据库失败:", err)
		return
	}
	defer dbMonitor.Close()
	// 创建表
	_, err = dbMonitor.Exec(`
	PRAGMA journal_mode=WAL;
	create table if not exists err_record
	(
		id          TEXT    not null
			constraint err_record_pk
				primary key,
		monitor_id  INTEGER not null,
		create_time TEXT    not null,
		info        TEXT    not null,
		msg         TEXT    not null
	);
	create index if not exists err_record_monitor_id_index
    	on err_record (monitor_id);
`)

	dbPrivateCa, err := sql.Open("sqlite", "data/private_ca.db")
	if err != nil {
		// fmt.Println("创建 private_ca 数据库失败:", err)
		return
	}
	defer dbPrivateCa.Close()
	// 创建表
	_, err = dbPrivateCa.Exec(`
	PRAGMA journal_mode=WAL;
	create table ca
	(
		id          integer         not null
			constraint ca_pk
				primary key autoincrement,
		root_id     integer,
		name        TEXT            not null,
		cn          TEXT            not null,
		o           TEXT default '' not null,
		c           TEXT            not null,
		cert        TEXT            not null,
		key         TEXT            not null,
		en_cert     TEXT,
		en_key      TEXT,
		algorithm   TEXT            not null,
		key_length  integer,
		not_before  TEXT            not null,
		not_after   TEXT            not null,
		create_time TEXT            not null
	);
	create index ca_root_id_index
		on ca (root_id);
	create table leaf
	(
		id          integer not null
			constraint leaf_pk
				primary key autoincrement,
		ca_id       integer not null,
		cn          TEXT    not null,
		san         TEXT    not null,
		usage       integer not null,
		cert        TEXT    not null,
		key         TEXT    not null,
		en_cert     TEXT,
		en_key      TEXT,
		algorithm   TEXT    not null,
		key_length  integer,
		not_before  TEXT    not null,
		not_after   TEXT    not null,
		create_time TEXT    not null
	);
	
	create index leaf_ca_id_index
		on leaf (ca_id);
`)

}

func insertDefaultData(db *sql.DB, table, insertSQL string) {
	// 查询用户表中现有的记录数
	var count int
	err := db.QueryRow("SELECT COUNT(*) FROM " + table).Scan(&count)
	if err != nil {
		// fmt.Println("检查数据行数失败:", err)
		return
	}

	// 如果表为空，则插入默认数据
	if count == 0 {
		// fmt.Println("表为空，插入默认数据...")
		_, err = db.Exec(insertSQL)
		if err != nil {
			// fmt.Println("插入数据失败:", err)
			return
		}
		// fmt.Println("默认数据插入成功。")
		// } else {
		// 	fmt.Println("表已有数据，跳过插入。")
	}
}

func InsertIfNotExists(
	db *sql.DB,
	table string,
	whereFields map[string]any, // 用于 WHERE 判断的字段和值
	insertColumns []string,
	insertValues []any,
) error {
	// 1. 构建 WHERE 子句
	whereClause := ""
	whereArgs := make([]any, 0, len(whereFields))
	i := 0
	for col, val := range whereFields {
		if i > 0 {
			whereClause += " AND "
		}
		whereClause += fmt.Sprintf("%s = ?", col)
		whereArgs = append(whereArgs, val)
		i++
	}

	// 2. 判断是否存在
	query := fmt.Sprintf("SELECT EXISTS(SELECT 1 FROM %s WHERE %s)", table, whereClause)
	var exists bool
	err := db.QueryRow(query, whereArgs...).Scan(&exists)
	if err != nil {
		return fmt.Errorf("check exists failed: %w", err)
	}
	if exists {
		return nil // 已存在
	}

	// 3. 构建 INSERT 语句
	columnList := ""
	placeholderList := ""
	for i, col := range insertColumns {
		if i > 0 {
			columnList += ", "
			placeholderList += ", "
		}
		columnList += col
		placeholderList += "?"
	}
	insertSQL := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)", table, columnList, placeholderList)

	_, err = db.Exec(insertSQL, insertValues...)
	if err != nil {
		return fmt.Errorf("insert failed: %w", err)
	}

	return nil
}
