package handler

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"
	"time"

	"sundynix-micro-go/app/gateway/internal/config"

	"github.com/zeromicro/go-zero/core/logx"
)

// ProxyRouter 反向代理路由器
type ProxyRouter struct {
	routes []*route
}

type route struct {
	prefix string
	proxy  *httputil.ReverseProxy
	target string
}

// NewProxyRouter 根据配置构建路由表
func NewProxyRouter(upstreams []config.Upstream) *ProxyRouter {
	router := &ProxyRouter{}

	for _, u := range upstreams {
		targetURL, err := url.Parse(u.Target)
		if err != nil {
			logx.Errorf("解析上游地址失败 [%s]: %v", u.Target, err)
			continue
		}

		target := targetURL // 显式捕获循环变量
		proxy := &httputil.ReverseProxy{
			Rewrite: func(pr *httputil.ProxyRequest) {
				pr.SetXForwarded()
				pr.Out.URL.Scheme = target.Scheme
				pr.Out.URL.Host = target.Host
				pr.Out.Host = target.Host
				// 路径透传：前端请求 /api/user/info -> 转发到 user-api 的 /api/user/info
				// 不剥前缀，后端API的路由本身就包含 /api/user 前缀
			},
		}

		// 自定义 Transport：超时控制
		proxy.Transport = &http.Transport{
			MaxIdleConns:          100,
			MaxIdleConnsPerHost:   20,
			IdleConnTimeout:       90 * time.Second,
			ResponseHeaderTimeout: 30 * time.Second, // 上游响应头超时，超出则触发 ErrorHandler
		}

		prefix := u.Prefix
		targetAddr := u.Target

		// ErrorHandler：处理网络层错误（连接失败、超时等）
		proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
			logx.Errorf("[Gateway] ❌ 上游连接失败 | %s %s -> %s | 错误: %v",
				r.Method, r.URL.Path, targetAddr, err)
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.WriteHeader(http.StatusBadGateway)
			fmt.Fprintf(w, `{"code":502,"msg":"上游服务不可用，请检查 %s 是否正常运行"}`, prefix)
		}

		// ModifyResponse：捕获上游返回的 4xx/5xx 并记录日志（网络层正常但业务异常）
		proxy.ModifyResponse = func(resp *http.Response) error {
			if resp.StatusCode >= 500 {
				// 读取响应体用于日志（最多 1KB，读完后要写回）
				body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024))
				resp.Body = io.NopCloser(bytes.NewBuffer(body))
				logx.Errorf("[Gateway] ⚠️  上游服务异常 | %s %s -> %s | 状态码: %d | 响应: %s",
					resp.Request.Method, resp.Request.URL.Path, targetAddr,
					resp.StatusCode, string(body))
			} else if resp.StatusCode >= 400 {
				logx.Infof("[Gateway] ℹ️  上游返回客户端错误 | %s %s | 状态码: %d",
					resp.Request.Method, resp.Request.URL.Path, resp.StatusCode)
			}
			return nil
		}

		router.routes = append(router.routes, &route{
			prefix: u.Prefix,
			proxy:  proxy,
			target: u.Target,
		})

		logx.Infof("路由注册: %s -> %s", u.Prefix, u.Target)
	}

	return router
}

// ServeHTTP 根据 URL 前缀匹配路由并转发
func (pr *ProxyRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	path := r.URL.Path

	for _, rt := range pr.routes {
		if strings.HasPrefix(path, rt.prefix) {
			logx.Infof("[Gateway] → %s %s -> %s", r.Method, path, rt.target)
			rt.proxy.ServeHTTP(w, r)
			return
		}
	}

	// 没有匹配的路由
	logx.Errorf("[Gateway] ❌ 路由未找到: %s %s", r.Method, path)
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.WriteHeader(http.StatusNotFound)
	fmt.Fprintf(w, `{"code":404,"msg":"路由未找到: %s"}`, path)
}
