package handler

import (
	"fmt"

	"github.com/gin-gonic/gin"
	"github.com/gotunnel/internal/server/db"
	"github.com/gotunnel/internal/server/router/dto"
	"github.com/gotunnel/pkg/plugin"
)

// PluginHandler 插件处理器
type PluginHandler struct {
	app AppInterface
}

// NewPluginHandler 创建插件处理器
func NewPluginHandler(app AppInterface) *PluginHandler {
	return &PluginHandler{app: app}
}

// List 获取插件列表
// @Summary 获取所有插件
// @Description 返回服务端所有注册的插件
// @Tags 插件
// @Produce json
// @Security Bearer
// @Success 200 {object} Response{data=[]dto.PluginInfo}
// @Router /api/plugins [get]
func (h *PluginHandler) List(c *gin.Context) {
	plugins := h.app.GetServer().GetPluginList()

	result := make([]dto.PluginInfo, len(plugins))
	for i, p := range plugins {
		result[i] = dto.PluginInfo{
			Name:        p.Name,
			Version:     p.Version,
			Type:        p.Type,
			Description: p.Description,
			Source:      p.Source,
			Icon:        p.Icon,
			Enabled:     p.Enabled,
		}
		if p.RuleSchema != nil {
			result[i].RuleSchema = &dto.RuleSchema{
				NeedsLocalAddr: p.RuleSchema.NeedsLocalAddr,
				ExtraFields:    convertRouterConfigFields(p.RuleSchema.ExtraFields),
			}
		}
	}

	Success(c, result)
}

// Enable 启用插件
// @Summary 启用插件
// @Description 启用指定插件
// @Tags 插件
// @Produce json
// @Security Bearer
// @Param name path string true "插件名称"
// @Success 200 {object} Response
// @Failure 400 {object} Response
// @Router /api/plugin/{name}/enable [post]
func (h *PluginHandler) Enable(c *gin.Context) {
	name := c.Param("name")

	if err := h.app.GetServer().EnablePlugin(name); err != nil {
		BadRequest(c, err.Error())
		return
	}

	Success(c, gin.H{"status": "ok"})
}

// Disable 禁用插件
// @Summary 禁用插件
// @Description 禁用指定插件
// @Tags 插件
// @Produce json
// @Security Bearer
// @Param name path string true "插件名称"
// @Success 200 {object} Response
// @Failure 400 {object} Response
// @Router /api/plugin/{name}/disable [post]
func (h *PluginHandler) Disable(c *gin.Context) {
	name := c.Param("name")

	if err := h.app.GetServer().DisablePlugin(name); err != nil {
		BadRequest(c, err.Error())
		return
	}

	Success(c, gin.H{"status": "ok"})
}

// GetRuleSchemas 获取规则配置模式
// @Summary 获取规则模式
// @Description 返回所有协议类型的配置模式
// @Tags 插件
// @Produce json
// @Security Bearer
// @Success 200 {object} Response{data=map[string]dto.RuleSchema}
// @Router /api/rule-schemas [get]
func (h *PluginHandler) GetRuleSchemas(c *gin.Context) {
	// 获取内置协议模式
	schemas := make(map[string]dto.RuleSchema)
	for name, schema := range plugin.BuiltinRuleSchemas() {
		schemas[name] = dto.RuleSchema{
			NeedsLocalAddr: schema.NeedsLocalAddr,
			ExtraFields:    convertConfigFields(schema.ExtraFields),
		}
	}

	// 添加已注册插件的模式
	plugins := h.app.GetServer().GetPluginList()
	for _, p := range plugins {
		if p.RuleSchema != nil {
			schemas[p.Name] = dto.RuleSchema{
				NeedsLocalAddr: p.RuleSchema.NeedsLocalAddr,
				ExtraFields:    convertRouterConfigFields(p.RuleSchema.ExtraFields),
			}
		}
	}

	Success(c, schemas)
}

// GetClientConfig 获取客户端插件配置
// @Summary 获取客户端插件配置
// @Description 获取客户端上指定插件的配置
// @Tags 插件
// @Produce json
// @Security Bearer
// @Param clientID path string true "客户端ID"
// @Param pluginName path string true "插件名称"
// @Success 200 {object} Response{data=dto.PluginConfigResponse}
// @Failure 404 {object} Response
// @Router /api/client-plugin/{clientID}/{pluginName}/config [get]
func (h *PluginHandler) GetClientConfig(c *gin.Context) {
	clientID := c.Param("clientID")
	pluginName := c.Param("pluginName")

	client, err := h.app.GetClientStore().GetClient(clientID)
	if err != nil {
		NotFound(c, "client not found")
		return
	}

	// 查找客户端的插件
	var clientPlugin *db.ClientPlugin
	for i, p := range client.Plugins {
		if p.Name == pluginName {
			clientPlugin = &client.Plugins[i]
			break
		}
	}

	if clientPlugin == nil {
		NotFound(c, "plugin not installed on client")
		return
	}

	var schemaFields []dto.ConfigField

	// 优先使用客户端插件保存的 ConfigSchema
	if len(clientPlugin.ConfigSchema) > 0 {
		for _, f := range clientPlugin.ConfigSchema {
			schemaFields = append(schemaFields, dto.ConfigField{
				Key:         f.Key,
				Label:       f.Label,
				Type:        f.Type,
				Default:     f.Default,
				Required:    f.Required,
				Options:     f.Options,
				Description: f.Description,
			})
		}
	} else {
		// 尝试从内置插件获取配置模式
		schema, err := h.app.GetServer().GetPluginConfigSchema(pluginName)
		if err != nil {
			// 如果内置插件中找不到，尝试从 JS 插件获取
			jsPlugin, jsErr := h.app.GetJSPluginStore().GetJSPlugin(pluginName)
			if jsErr == nil {
				// 使用 JS 插件的 config 作为动态 schema
				for key := range jsPlugin.Config {
					schemaFields = append(schemaFields, dto.ConfigField{
						Key:   key,
						Label: key,
						Type:  "string",
					})
				}
			}
		} else {
			schemaFields = convertRouterConfigFields(schema)
		}
	}

	// 添加 remote_port 作为系统配置字段（始终显示）
	schemaFields = append([]dto.ConfigField{{
		Key:         "remote_port",
		Label:       "远程端口",
		Type:        "number",
		Description: "服务端监听端口，修改后需重启插件生效",
	}}, schemaFields...)

	// 添加 Auth 配置字段
	schemaFields = append(schemaFields, dto.ConfigField{
		Key:         "auth_enabled",
		Label:       "启用认证",
		Type:        "bool",
		Description: "启用 HTTP Basic Auth 保护",
	}, dto.ConfigField{
		Key:         "auth_username",
		Label:       "认证用户名",
		Type:        "string",
		Description: "HTTP Basic Auth 用户名",
	}, dto.ConfigField{
		Key:         "auth_password",
		Label:       "认证密码",
		Type:        "password",
		Description: "HTTP Basic Auth 密码",
	})

	// 构建配置值
	config := clientPlugin.Config
	if config == nil {
		config = make(map[string]string)
	}
	// 将 remote_port 加入配置
	if clientPlugin.RemotePort > 0 {
		config["remote_port"] = fmt.Sprintf("%d", clientPlugin.RemotePort)
	}
	// 将 Auth 配置加入
	if clientPlugin.AuthEnabled {
		config["auth_enabled"] = "true"
	} else {
		config["auth_enabled"] = "false"
	}
	config["auth_username"] = clientPlugin.AuthUsername
	config["auth_password"] = clientPlugin.AuthPassword

	Success(c, dto.PluginConfigResponse{
		PluginName: pluginName,
		Schema:     schemaFields,
		Config:     config,
	})
}

// UpdateClientConfig 更新客户端插件配置
// @Summary 更新客户端插件配置
// @Description 更新客户端上指定插件的配置
// @Tags 插件
// @Accept json
// @Produce json
// @Security Bearer
// @Param clientID path string true "客户端ID"
// @Param pluginName path string true "插件名称"
// @Param request body dto.PluginConfigRequest true "配置内容"
// @Success 200 {object} Response
// @Failure 400 {object} Response
// @Failure 404 {object} Response
// @Router /api/client-plugin/{clientID}/{pluginName}/config [put]
func (h *PluginHandler) UpdateClientConfig(c *gin.Context) {
	clientID := c.Param("clientID")
	pluginName := c.Param("pluginName")

	var req dto.PluginConfigRequest
	if !BindJSON(c, &req) {
		return
	}

	client, err := h.app.GetClientStore().GetClient(clientID)
	if err != nil {
		NotFound(c, "client not found")
		return
	}

	// 更新插件配置
	found := false
	portChanged := false
	authChanged := false
	var oldPort, newPort int
	for i, p := range client.Plugins {
		if p.Name == pluginName {
			oldPort = client.Plugins[i].RemotePort
			// 提取 remote_port 并单独处理
			if portStr, ok := req.Config["remote_port"]; ok {
				fmt.Sscanf(portStr, "%d", &newPort)
				if newPort > 0 && newPort != oldPort {
					// 检查新端口是否可用
					if !h.app.GetServer().IsPortAvailable(newPort, clientID) {
						BadRequest(c, fmt.Sprintf("port %d is already in use", newPort))
						return
					}
					client.Plugins[i].RemotePort = newPort
					portChanged = true
				}
				delete(req.Config, "remote_port") // 不保存到 Config map
			}
			// 提取 Auth 配置并单独处理
			if authEnabledStr, ok := req.Config["auth_enabled"]; ok {
				newAuthEnabled := authEnabledStr == "true"
				if newAuthEnabled != client.Plugins[i].AuthEnabled {
					client.Plugins[i].AuthEnabled = newAuthEnabled
					authChanged = true
				}
				delete(req.Config, "auth_enabled")
			}
			if authUsername, ok := req.Config["auth_username"]; ok {
				if authUsername != client.Plugins[i].AuthUsername {
					client.Plugins[i].AuthUsername = authUsername
					authChanged = true
				}
				delete(req.Config, "auth_username")
			}
			if authPassword, ok := req.Config["auth_password"]; ok {
				if authPassword != client.Plugins[i].AuthPassword {
					client.Plugins[i].AuthPassword = authPassword
					authChanged = true
				}
				delete(req.Config, "auth_password")
			}
			client.Plugins[i].Config = req.Config
			found = true
			break
		}
	}

	if !found {
		NotFound(c, "plugin not installed on client")
		return
	}

	// 如果端口变更，同步更新代理规则
	if portChanged {
		for i, r := range client.Rules {
			if r.Name == pluginName && r.PluginManaged {
				client.Rules[i].RemotePort = newPort
				break
			}
		}
		// 停止旧端口监听器
		if oldPort > 0 {
			h.app.GetServer().StopPluginRule(clientID, oldPort)
		}
	}

	// 如果 Auth 配置变更，同步更新代理规则
	if authChanged {
		for i, p := range client.Plugins {
			if p.Name == pluginName {
				for j, r := range client.Rules {
					if r.Name == pluginName && r.PluginManaged {
						client.Rules[j].AuthEnabled = client.Plugins[i].AuthEnabled
						client.Rules[j].AuthUsername = client.Plugins[i].AuthUsername
						client.Rules[j].AuthPassword = client.Plugins[i].AuthPassword
						break
					}
				}
				break
			}
		}
	}

	// 保存到数据库
	if err := h.app.GetClientStore().UpdateClient(client); err != nil {
		InternalError(c, err.Error())
		return
	}

	// 如果客户端在线，同步配置
	if h.app.GetServer().IsClientOnline(clientID) {
		if err := h.app.GetServer().SyncPluginConfigToClient(clientID, pluginName, req.Config); err != nil {
			PartialSuccess(c, gin.H{"status": "partial", "port_changed": portChanged}, "config saved but sync failed: "+err.Error())
			return
		}
	}

	Success(c, gin.H{"status": "ok", "port_changed": portChanged})
}

// convertConfigFields 转换插件配置字段到 DTO
func convertConfigFields(fields []plugin.ConfigField) []dto.ConfigField {
	result := make([]dto.ConfigField, len(fields))
	for i, f := range fields {
		result[i] = dto.ConfigField{
			Key:         f.Key,
			Label:       f.Label,
			Type:        string(f.Type),
			Default:     f.Default,
			Required:    f.Required,
			Options:     f.Options,
			Description: f.Description,
		}
	}
	return result
}

// convertRouterConfigFields 转换 ConfigField 到 dto.ConfigField
func convertRouterConfigFields(fields []ConfigField) []dto.ConfigField {
	result := make([]dto.ConfigField, len(fields))
	for i, f := range fields {
		result[i] = dto.ConfigField{
			Key:         f.Key,
			Label:       f.Label,
			Type:        f.Type,
			Default:     f.Default,
			Required:    f.Required,
			Options:     f.Options,
			Description: f.Description,
		}
	}
	return result
}
