// Copyright 2013 bee authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package migrate

import (
	"os"

	"container/list"
	"fmt"
	"log"

	"github.com/TruthHun/BookStack/models"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"
)

var (
	migrationList = &migrationCache{}
)

type MigrationDatabase interface {
	//获取当前的版本
	Version() int64
	//校验当前是否可更新
	ValidUpdate(version int64) error
	//校验并备份表结构
	ValidForBackupTableSchema() error
	//校验并更新表结构
	ValidForUpdateTableSchema() error
	//恢复旧数据
	MigrationOldTableData() error
	//插入新数据
	MigrationNewTableData() error
	//增加迁移记录
	AddMigrationRecord(version int64) error
	//最后的清理工作
	MigrationCleanup() error
	//回滚本次迁移
	RollbackMigration() error
}

type migrationCache struct {
	items *list.List
}

func RunMigration() {

	if len(os.Args) >= 2 && os.Args[1] == "migrate" {

		migrate, err := models.NewMigration().FindFirst()

		if err != nil {
			//log.Fatalf("migrations table %s", err)
			migrate = models.NewMigration()
		}
		fmt.Println("Start migration databae... ")

		for el := migrationList.items.Front(); el != nil; el = el.Next() {

			//如果存在比当前版本大的版本，则依次升级
			if item, ok := el.Value.(MigrationDatabase); ok && item.Version() > migrate.Version {
				err := item.ValidUpdate(migrate.Version)
				if err != nil {
					log.Fatal(err)
				}
				err = item.ValidForBackupTableSchema()
				if err != nil {
					item.RollbackMigration()
					log.Fatal(err)
				}
				err = item.ValidForUpdateTableSchema()
				if err != nil {
					item.RollbackMigration()
					log.Fatal(err)
				}
				err = item.MigrationOldTableData()
				if err != nil {
					item.RollbackMigration()
					log.Fatal(err)
				}
				err = item.MigrationNewTableData()
				if err != nil {
					item.RollbackMigration()
					log.Fatal(err)
				}
				err = item.AddMigrationRecord(item.Version())
				if err != nil {
					item.RollbackMigration()
					log.Fatal(err)
				}
				err = item.MigrationCleanup()
				if err != nil {
					item.RollbackMigration()
					log.Fatal(err)
				}
			}
		}
		fmt.Println("Migration successfull.")
		os.Exit(0)
	}
}

//导出数据库的表结构
func ExportDatabaseTable() ([]string, error) {
	db_adapter := beego.AppConfig.String("db_adapter")
	db_database := beego.AppConfig.String("db_database")
	tables := make([]string, 0)

	o := orm.NewOrm()
	switch db_adapter {
	case "mysql":
		{
			var lists []orm.Params

			_, err := o.Raw(fmt.Sprintf("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '%s'", db_database)).Values(&lists)
			if err != nil {
				return tables, err
			}
			for _, table := range lists {
				var results []orm.Params

				_, err = o.Raw(fmt.Sprintf("show create table %s", table["TABLE_NAME"])).Values(&results)
				if err != nil {
					return tables, err
				}
				tables = append(tables, results[0]["Create Table"].(string))
			}
			break
		}
	case "sqlite3":
		{
			var results []orm.Params
			_, err := o.Raw("SELECT sql FROM sqlite_master WHERE sql IS NOT NULL ORDER BY rootpage ASC").Values(&results)
			if err != nil {
				return tables, err
			}
			for _, item := range results {
				if sql, ok := item["sql"]; ok {
					tables = append(tables, sql.(string))
				}
			}
			break
		}

	}
	return tables, nil
}

func RegisterMigration() {
	migrationList.items = list.New()

	migrationList.items.PushBack(NewMigrationVersion03())
}
