package mcp

import (
	"context"
	"fmt"

	"github.com/kami/maven/internal/webfetch"
)

// WebfetchDoor builds the PosterFactory used in production: one guarded
// webfetch.Fetcher per url server, with that server's allow_private and the
// shared host lists and limits.
//
// One fetcher PER server is the point. allow_private is a hole in the
// private-address guard, and a hole punched for the Vikunja server on loopback
// must not become a hole for some public endpoint that happens to redirect at
// the LAN. Rate limiting is per fetcher too, which is the right shape here:
// separate servers are separate hosts.
//
// A server WITH allow_private also gets redirects switched off. Across servers
// the per-fetcher split holds the line; within the one server that has the
// flag it did not, because allow_private disables the dialer guard on every
// hop: http://localhost:9100/mcp answering 302 to
// http://169.254.169.254/latest/meta-data/ was followed, up to MaxRedirects. A
// local MCP endpoint has no business redirecting, so refusing costs nothing.
func WebfetchDoor(limits webfetch.Config) PosterFactory {
	return func(cfg ServerConfig) (Poster, error) {
		c := limits
		c.AllowPrivate = cfg.AllowPrivate
		if cfg.AllowPrivate {
			c.MaxRedirects = -1 // negative ⇒ no redirects followed
		}
		if c.Timeout <= 0 && cfg.Timeout > 0 {
			c.Timeout = cfg.Timeout
		}
		return fetcherPoster{webfetch.New(c)}, nil
	}
}

// fetcherPoster adapts webfetch.Fetcher to Poster. It exists so this package
// does not have to know webfetch's Response type, and so a test can substitute
// a fake without a listener.
type fetcherPoster struct{ f *webfetch.Fetcher }

func (p fetcherPoster) Post(ctx context.Context, rawURL, contentType string, body []byte, hdr map[string]string) (*PostResponse, error) {
	resp, err := p.f.Post(ctx, rawURL, contentType, body, hdr)
	if err != nil {
		return nil, fmt.Errorf("mcp: post %s: %w", rawURL, err)
	}
	return &PostResponse{
		Status:      resp.Status,
		ContentType: resp.ContentType,
		Body:        resp.Body,
		Header:      resp.Header,
	}, nil
}
