// Package module defines the small contracts shared by application modules.
// A module contributes its own schema, seed data, admin surface and runtime
// hooks without depending on the built-in system implementation.
package module

import (
	"github.com/gin-gonic/gin"
	"kra/pkg/database/migration"
	"kra/pkg/task"
)

type Menu struct {
	Name, Path, ParentName, Component, Title, Icon string
	Sort                                           int
}

type API struct {
	Path, Method, Group, Description string
}

type Surface struct {
	Menus []Menu
	APIs  []API
}

type TimedTask struct {
	Name, Description, Spec, MethodName string
	WithSeconds, Enabled                bool
}

type Definition struct {
	Name       string
	Migrations []migration.Step
	Surface    Surface
	TimedTasks []TimedTask
	Tasks      []task.Method
}

type Catalog struct {
	Definitions []Definition
}

func (c Catalog) MigrationSteps() []migration.Step {
	var steps []migration.Step
	for _, item := range c.Definitions {
		steps = append(steps, item.Migrations...)
	}
	return steps
}

func (c Catalog) Surface() Surface {
	var surface Surface
	for _, item := range c.Definitions {
		surface.Menus = append(surface.Menus, item.Surface.Menus...)
		surface.APIs = append(surface.APIs, item.Surface.APIs...)
	}
	return surface
}

func (c Catalog) DefaultTimedTasks() []TimedTask {
	var tasks []TimedTask
	for _, item := range c.Definitions {
		tasks = append(tasks, item.TimedTasks...)
	}
	return tasks
}

func (c Catalog) TaskMethods() []task.Method {
	var methods []task.Method
	for _, item := range c.Definitions {
		methods = append(methods, item.Tasks...)
	}
	return methods
}

type RouteRegistrar interface {
	RegisterRoutes(public, private *gin.RouterGroup, engine *gin.Engine)
}

type Runtime struct {
	routes []RouteRegistrar
}

func NewRuntime(routes ...RouteRegistrar) *Runtime {
	return &Runtime{routes: append([]RouteRegistrar(nil), routes...)}
}

func (r *Runtime) Add(routes ...RouteRegistrar) {
	if r == nil {
		return
	}
	r.routes = append(r.routes, routes...)
}

func (r *Runtime) RegisterRoutes(public, private *gin.RouterGroup, engine *gin.Engine) {
	if r == nil {
		return
	}
	for _, registrar := range r.routes {
		registrar.RegisterRoutes(public, private, engine)
	}
}
