// Package server 提供 HTTP 服务器核心功能。
//
// 该文件实现缓存清理 API 处理器，支持主动清理代理缓存。
package server

import (
	"encoding/json"
	"net"

	"github.com/valyala/fasthttp"
	"rua.plus/lolly/internal/cache"
	"rua.plus/lolly/internal/config"
	"rua.plus/lolly/internal/utils"
)

// PurgeHandler 缓存清理 API 处理器。
//
// 持有 Server 引用以访问所有代理实例的缓存。
// 支持 IP 白名单和 Token 认证保护。
//
// 注意事项：
//   - 仅处理 POST 请求
//   - 支持按路径和按模式两种清理方式
//   - method 参数支持指定 HTTP 方法（默认 GET）
type PurgeHandler struct {
	server  *Server
	auth    config.CacheAPIAuthConfig
	path    string
	allowed []net.IPNet
}

// NewPurgeHandler 创建缓存清理 API 处理器。
//
// 解析 IP 白名单配置，支持 CIDR 格式和单个 IP。
// localhost 特殊处理为 127.0.0.1 和 ::1。
//
// 参数：
//   - server: Server 实例，用于访问代理缓存
//   - cfg: CacheAPI 配置
//
// 返回值：
//   - *PurgeHandler: 配置好的处理器
//   - error: IP 解析失败时返回非 nil 错误
func NewPurgeHandler(server *Server, cfg *config.CacheAPIConfig) (*PurgeHandler, error) {
	h := &PurgeHandler{
		server: server,
		path:   cfg.Path,
		auth:   cfg.Auth,
	}

	// 默认路径
	if h.path == "" {
		h.path = "/_cache/purge"
	}

	// 解析允许的 IP 列表
	allowed, err := utils.ParseIPAllowList(cfg.Allow)
	if err != nil {
		return nil, err
	}
	h.allowed = allowed

	return h, nil
}

// Path 返回 API 端点路径。
func (h *PurgeHandler) Path() string {
	return h.path
}

// ServeHTTP 处理缓存清理请求。
//
// 仅处理 POST 请求，支持精确路径和通配符模式清理。
// 返回 JSON 格式的响应。
func (h *PurgeHandler) ServeHTTP(ctx *fasthttp.RequestCtx) {
	// 仅允许 POST 方法
	if string(ctx.Method()) != "POST" {
		utils.SendJSONError(ctx, fasthttp.StatusMethodNotAllowed, "method not allowed")
		return
	}

	// 检查 IP 访问权限
	if !utils.CheckIPAccess(ctx, h.allowed) {
		utils.SendJSONError(ctx, fasthttp.StatusForbidden, "forbidden")
		return
	}

	// 检查认证
	if !utils.CheckTokenAuth(ctx, h.auth) {
		utils.SendJSONError(ctx, fasthttp.StatusUnauthorized, "unauthorized")
		return
	}

	// 解析请求体
	var req cache.PurgeRequest
	if err := json.Unmarshal(ctx.PostBody(), &req); err != nil {
		utils.SendJSONError(ctx, fasthttp.StatusBadRequest, "invalid request body")
		return
	}

	// 执行清理
	deleted := 0
	if req.Path != "" {
		deleted = h.purgeByPath(req.Path, req.Method)
	} else if req.Pattern != "" {
		deleted = h.purgeByPattern(req.Pattern, req.Method)
	} else {
		utils.SendJSONError(ctx, fasthttp.StatusBadRequest, "missing path or pattern")
		return
	}

	// 返回响应
	ctx.SetContentType("application/json; charset=utf-8")
	ctx.SetStatusCode(fasthttp.StatusOK)
	_ = json.NewEncoder(ctx).Encode(cache.PurgeResponse{Deleted: deleted})
}

// purgeByPath 按精确路径清理缓存。
func (h *PurgeHandler) purgeByPath(path string, method string) int {
	if h.server == nil {
		return 0
	}

	hashKey := cache.HashPathWithMethod(path, method)
	deleted := 0

	h.server.proxiesMu.RLock()
	for _, p := range h.server.proxies {
		if pcache := p.GetCache(); pcache != nil {
			_ = pcache.Delete(hashKey)
			deleted++
		}
	}
	h.server.proxiesMu.RUnlock()

	return deleted
}

// purgeByPattern 按通配符模式清理缓存。
func (h *PurgeHandler) purgeByPattern(pattern string, method string) int {
	if h.server == nil {
		return 0
	}

	deleted := 0

	h.server.proxiesMu.RLock()
	for _, p := range h.server.proxies {
		if pcache := p.GetCache(); pcache != nil {
			deleted += pcache.DeleteByPatternWithMethod(pattern, method)
		}
	}
	h.server.proxiesMu.RUnlock()

	return deleted
}
