// Copyright 2026 MarketAlly. All rights reserved.
// SPDX-License-Identifier: MIT

// Gitea MCP Server - Model Context Protocol server for Gitea Actions
//
// This standalone server implements the MCP protocol over stdio,
// proxying requests to a Gitea instance's /api/v2/mcp endpoint.
//
// Usage:
//
//	gitea-mcp-server --url https://git.example.com --token YOUR_API_TOKEN
//
// Configure in Claude Code's settings.json:
//
//	{
//	  "mcpServers": {
//	    "gitea": {
//	      "command": "gitea-mcp-server",
//	      "args": ["--url", "https://git.example.com", "--token", "YOUR_TOKEN"]
//	    }
//	  }
//	}
package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io"
	"net/http"
	"os"
	"time"

	"code.gitea.io/gitea/modules/json"
)

var (
	giteaURL   string
	giteaToken string
	debug      bool
)

func main() {
	flag.StringVar(&giteaURL, "url", "", "Gitea server URL (e.g., https://git.example.com)")
	flag.StringVar(&giteaToken, "token", "", "Gitea API token")
	flag.BoolVar(&debug, "debug", false, "Enable debug logging to stderr")
	flag.Parse()

	// Also check environment variables
	if giteaURL == "" {
		giteaURL = os.Getenv("GITEA_URL")
	}
	if giteaToken == "" {
		giteaToken = os.Getenv("GITEA_TOKEN")
	}

	if giteaURL == "" {
		fmt.Fprintln(os.Stderr, "Error: --url or GITEA_URL is required")
		os.Exit(1)
	}

	debugLog("Gitea MCP Server starting")
	debugLog("Connecting to: %s", giteaURL)

	// Read JSON-RPC messages from stdin, forward to Gitea, write responses to stdout
	reader := bufio.NewReader(os.Stdin)

	for {
		line, err := reader.ReadBytes('\n')
		if err != nil {
			if err == io.EOF {
				debugLog("EOF received, exiting")
				break
			}
			debugLog("Read error: %v", err)
			continue
		}

		line = bytes.TrimSpace(line)
		if len(line) == 0 {
			continue
		}

		debugLog("Received: %s", string(line))

		// Forward to Gitea's MCP endpoint
		response, err := forwardToGitea(line)
		if err != nil {
			debugLog("Forward error: %v", err)
			// Send error response
			errorResp := map[string]any{
				"jsonrpc": "2.0",
				"id":      nil,
				"error": map[string]any{
					"code":    -32603,
					"message": "Internal error",
					"data":    err.Error(),
				},
			}
			writeResponse(errorResp)
			continue
		}

		debugLog("Response: %s", string(response))

		// Write response to stdout
		fmt.Println(string(response))
	}
}

func forwardToGitea(request []byte) ([]byte, error) {
	mcpURL := giteaURL + "/api/v2/mcp"

	req, err := http.NewRequest(http.MethodPost, mcpURL, bytes.NewReader(request))
	if err != nil {
		return nil, fmt.Errorf("create request: %w", err)
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "application/json")
	if giteaToken != "" {
		req.Header.Set("Authorization", "token "+giteaToken)
	}

	client := &http.Client{Timeout: 30 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("http request: %w", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("read response: %w", err)
	}

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("http status %d: %s", resp.StatusCode, string(body))
	}

	return body, nil
}

func writeResponse(resp any) {
	data, _ := json.Marshal(resp)
	fmt.Println(string(data))
}

func debugLog(format string, args ...any) {
	if debug {
		fmt.Fprintf(os.Stderr, "[DEBUG] "+format+"\n", args...)
	}
}
