package core

import (
	"bytes"
	"dbweb/lib/bill"
	"dbweb/lib/model"
	"fmt"
	"html/template"

	"github.com/linlexing/dbx/ddb"
)

var (
	controllers     = map[string]*Controller{}
	controllerNames = []string{}
)

//系统事件的接口
type SystemLoginEvent interface {
	OnSystemLogin(p *ElementHandleArgs)
}
type controllerInitEvent interface {
	OnControllerInit(db ddb.TxDB) error
}

//动态获取Bill的接口
type BuildBillEvent interface {
	Bill(p *ElementHandleArgs) *bill.Bill
}

//动态获取DBName的接口
type GetDBNameEvent interface {
	DBName(p *ElementHandleArgs) string
}

type Controller struct {
	Name          string
	Layout        string
	Bill          bool
	ModelName     string
	AppController interface{}
}

//initControllers 初始化所有的controller
func initControllers(metaDB ddb.TxDB) {
	for _, c := range controllers {
		if tc, ok := c.AppController.(controllerInitEvent); ok {
			LOG.Println("call controller", c.Name, "init event")
			if err := tc.OnControllerInit(metaDB); err != nil {
				LOG.Panic(err)
			}
		}
	}
}

//Model 返回ModelName对应的Model，在调用此函数前，确保对应ModelName的Model已经注册
func (c *Controller) Model() *model.Model {
	return LoadModel(c.ModelName)
}

//DBName 返回对应Model所操纵的DBName，在调用此函数前，确保对应ModelName的Model已经注册
func (c *Controller) DBName() string {
	return mustFindModel(c.ModelName).dbname
}

//CallSystemLoginEvent 在用户登录时触发
func CallSystemLoginEvent(p *ElementHandleArgs) {
	for _, v := range controllers {
		if evt, ok := v.AppController.(SystemLoginEvent); ok {
			evt.OnSystemLogin(p)
		}
	}
}

//RegisterBill 注册一个单据
func RegisterBill(Name string, AppController interface{}, ModelName string, Layout ...string) {
	//因为这个函数一般是在init中调用，那时，还没有初始化日志
	checkLog()
	if len(Layout) > 1 {
		LOG.Panic("Layout must of 1 param")
	}

	var layout string
	if len(Layout) == 1 {
		layout = Layout[0]
	}
	if md := modelList.FindByName(ModelName); md == nil {
		LOG.Println(Name, "no model")
	}

	register(&Controller{
		Name:          Name,
		AppController: AppController,
		ModelName:     ModelName,
		Bill:          true,
		Layout:        layout,
	})
}

//RegisterFun 注册一个功能
func RegisterFun(Name string, AppController interface{}, Layout ...string) {
	//因为这个函数一般是在init中调用，那时，还没有初始化日志
	checkLog()
	if len(Layout) > 1 {
		LOG.Panic("too long layout")
	}
	var layout string
	if len(Layout) == 1 {
		layout = Layout[0]
	}
	register(&Controller{
		Name:          Name,
		AppController: AppController,
		Layout:        layout,
	})
}
func register(ctl *Controller) {
	if ctl.AppController == nil {
		LOG.Panic("no app controller:" + ctl.Name)
	}
	if _, ok := controllers[ctl.Name]; ok {
		LOG.Panic("ctrl:" + ctl.Name + " exists")
	}
	controllers[ctl.Name] = ctl
	controllerNames = append(controllerNames, ctl.Name)
}
func ControllerNames() []string {

	return controllerNames
}
func FindController(name string) *Controller {
	if v, ok := controllers[name]; ok {
		return v
	}
	return nil
}
func (c *Controller) NewBill(metadb ddb.DB) *bill.Bill {
	if _, ok := c.AppController.(BuildBillEvent); ok {
		LOG.Panic("the bill event can't call by Controller.NewBill")
	} else {
		md := LoadModel(c.ModelName)
		if md == nil {
			LOG.Panic("model", c.ModelName, "not found")
		}
		return LoadModel(c.ModelName).Bill()
	}
	return nil
}
func (c *Controller) Handle(args *ElementHandleArgs) {
	t := args.Render.Template()
	t.Funcs(template.FuncMap{
		"include": func(name string, pam interface{}) template.HTML {
			out := bytes.NewBuffer(nil)
			if err := t.ExecuteTemplate(out, name, pam); err != nil {
				LOG.Panic(err)
			}
			return template.HTML(out.Bytes())
		},
	})

	if c.Bill {
		switch args.Req.Method {
		case "GET":
			f, ok := c.AppController.(BillGetEvent)
			if !ok {
				f = BillGetEvent(defaultBill)
			}
			billArgs := NewBillGetHandleArgs(args)
			if billArgs.Record == nil && (billArgs.Param.Operate == "edit" ||
				billArgs.Param.Operate == "delete" ||
				billArgs.Param.Operate == "browse") {
				billArgs.RenderError(fmt.Sprintf("找不到[%s]中%v值为:%v的记录",
					billArgs.Bill.Main.FullName(),
					billArgs.Bill.Main.PrimaryKeys,
					args.PKS))
				return
			}
			f.Get(billArgs)

		case "POST":
			f, ok := c.AppController.(BillPostEvent)
			if !ok {
				LOG.Println("use default bill")
				f = BillPostEvent(defaultBill)
			}
			billArgs := NewBillPostHandleArgs(args)

			f.Post(billArgs)
		case "DELETE":
			f, ok := c.AppController.(BillDeleteEvent)
			if !ok {
				f = BillDeleteEvent(defaultBill)
			}
			billArgs := NewBillDeleteHandleArgs(args)

			f.Delete(billArgs)
		}

	} else {
		switch args.Req.Method {
		case "GET":
			f, ok := c.AppController.(GetEvent)
			if !ok {
				f = GetEvent(defaultCtrl)
			}
			f.Get(args)
		case "POST":
			f, ok := c.AppController.(PostEvent)
			if !ok {
				f = PostEvent(defaultCtrl)
			}
			f.Post(args)
		case "DELETE":
			f, ok := c.AppController.(DeleteEvent)
			if !ok {
				f = DeleteEvent(defaultCtrl)
			}
			f.Delete(args)
		}
	}
}
