package common

import (
	"dbweb/core"
	"dbweb/lib/safe"
	"dbweb/modules/common/recordview"
	"fmt"
	"strings"
	"time"

	"github.com/linlexing/dbx/ddb"

	"github.com/linlexing/dbx/schema"
)

//RemoveSel 类
type RemoveSel struct{}
type removeSelTaskParam struct {
	DBName      string
	Table       string
	UniqueField []string
	DataSQL     string
}

func init() {
	core.RegisterFun("removesel", new(RemoveSel), "_layout/blank")
}

//Post 业务
func (e *RemoveSel) Post(p *core.ElementHandleArgs) {
	rparams := recordview.GetCallParam(p)

	if rparams == nil {
		p.RenderTimeout()
		return
	}
	fromRecordView := rparams.FromRecordView(p.DB)
	eleParam := fromRecordView.Params
	dataDB := core.LoadOuterDB(p.DB, rparams.Select.DBName)
	var vCount int64
	if err := dataDB.QueryRow(fmt.Sprintf("select count(*) from (%s) exp_sql", rparams.Select.DataSQL())).
		Scan(&vCount); err != nil {
		core.LOG.Panic(err)
	}
	config := removeSelTaskParam{
		DBName:      rparams.Select.DBName,
		UniqueField: eleParam.UniqueField,
		Table:       rparams.Select.TableName,
		DataSQL:     rparams.Select.DataSQL(),
	}
	task := &core.TaskRun{
		Db:       p.DB,
		Name:     fmt.Sprintf("%s 删除%d条记录", fromRecordView.DisplayLabel(), safe.Int(vCount)),
		User:     p.User,
		ClientIP: p.Req.RemoteAddr,
		Param:    config,
		Func:     e.doDelete,
		LSession: p.LSession,
	}
	if err := task.GoRun(); err != nil {
		p.RenderError(err.Error())

	} else {
		p.RenderMessage(fmt.Sprintf("删除操作将在后台运行，可以<a href='%s' target='_blank'>点击查看进度</a>", p.User.Sign("/browsetask/"+task.ID())))
	}
}
func (e *RemoveSel) doDelete(t *core.TaskRun) string {
	param := t.Param.(removeSelTaskParam)
	dataDB := core.LoadOuterDB(t.Db, param.DBName)
	startTime := time.Now()
	var icount int64
	destTable, err := schema.Find(dataDB.DriverName()).OpenTable(dataDB, param.Table)
	if err != nil {
		core.LOG.Panic(err)
	}
	pkWhere := []string{}
	for i, v := range destTable.PrimaryKeys {
		//eleParam.UniqueField中的名称可能与实际的字段名不一致
		pkWhere = append(pkWhere, fmt.Sprintf("src.%s=dest.%s", param.UniqueField[i], v))
	}
	//mysql 需要特殊处理
	if dataDB.DriverName() == "mysql" {
		if err := ddb.RunAtTx(dataDB, func(tx ddb.Txer) (err error) {
			if _, err = tx.Exec(fmt.Sprintf(
				"create TEMPORARY TABLE tmp_delpks AS (SELECT %s FROM (%s) tmpcrt)",
				strings.Join(param.UniqueField, ","), param.DataSQL)); err != nil {
				return
			}
			if _, err = tx.Exec(fmt.Sprintf(
				"ALTER TABLE tmp_delpks ADD PRIMARY KEY(%s)",
				strings.Join(param.UniqueField, ","))); err != nil {
				return
			}
			sr, err := tx.Exec(fmt.Sprintf(
				"delete dest.* from %s dest inner join tmp_delpks src on %s",
				param.Table, strings.Join(pkWhere, " and\n")))
			if err != nil {
				return
			}
			icount, err = sr.RowsAffected()
			if err != nil {
				core.LOG.Panic(err)
			}
			return
		}); err != nil {
			core.LOG.Panic(err)
		}

	} else {
		strDelete := fmt.Sprintf(
			"delete from %s dest where exists(select 1 from (%s) src where %s)",
			param.Table, param.DataSQL, strings.Join(pkWhere, " and\n"))
		sr, err := dataDB.Exec(strDelete)
		if err != nil {
			core.LOG.Panic(err)
		}

		icount, err = sr.RowsAffected()
		if err != nil {
			core.LOG.Panic(err)
		}

	}

	return fmt.Sprintf("%d record removed,used time:%.2fs.", icount, time.Since(startTime).Seconds())
}

//Get 业务
func (e *RemoveSel) Get(p *core.ElementHandleArgs) {
	rparams := recordview.GetCallParam(p)

	if rparams == nil {
		p.RenderTimeout()
		return
	}
	dataDB := core.LoadOuterDB(p.DB, rparams.Select.DBName)
	fromRecordView := rparams.FromRecordView(p.DB)
	var vCount int64
	if err := dataDB.QueryRow(fmt.Sprintf("select count(*) from (%s) exp_sql", rparams.Select.DataSQL())).
		Scan(&vCount); err != nil {
		core.LOG.Panic(err)
	}
	p.More["FromElement"] = fromRecordView
	p.More["RowCount"] = safe.Int(vCount)
	p.HTML()
}
