package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"net/http"
	"os"
	"strconv"
)

func getEnv(key, defaultVal string) string {
	if value, exists := os.LookupEnv(key); exists {
		return value
	}
	return defaultVal
}

func main() {
	// Define command-line flags with environment variable defaults
	var forgejoAPIURL string
	flag.StringVar(&forgejoAPIURL, "forgejo-api-url", getEnv("FORGEJO_API_URL", "https://code.252.no/api/v1"), "Forgejo API URL (default: https://code.252.no/api/v1 or $FORGEJO_API_URL)")

	var token string
	flag.StringVar(&token, "token", os.Getenv("FORGEJO_TOKEN"), "Forgejo API token (required, or set $FORGEJO_TOKEN)")

	var repoOwner string
	flag.StringVar(&repoOwner, "repo-owner", os.Getenv("REPO_OWNER"), "Repository owner (required, or set $REPO_OWNER)")

	var repoName string
	flag.StringVar(&repoName, "repo-name", os.Getenv("REPO_NAME"), "Repository name (required, or set $REPO_NAME)")

	var issueId int
	issueIdStr := os.Getenv("ISSUE_ID")
	if issueIdStr != "" {
		var err error
		issueId, err = strconv.Atoi(issueIdStr)
		if err != nil {
			fmt.Println("Error: Invalid ISSUE_ID")
			os.Exit(1)
		}
	}
	flag.IntVar(&issueId, "issue-id", issueId, "Issue ID to comment on (cannot be used with --pull-id, or set $ISSUE_ID)")

	var pullId int
	pullIdStr := os.Getenv("PULL_ID")
	if pullIdStr != "" {
		var err error
		pullId, err = strconv.Atoi(pullIdStr)
		if err != nil {
			fmt.Println("Error: Invalid PULL_ID")
			os.Exit(1)
		}
	}
	flag.IntVar(&pullId, "pull-id", pullId, "Pull Request ID to comment on (cannot be used with --issue-id, or set $PULL_ID)")

	// Override the default usage message to be more helpful
	flag.Usage = func() {
		fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [options] <diff-file>\n", os.Args[0])
		fmt.Fprintln(flag.CommandLine.Output(), "\nOptions:")
		flag.PrintDefaults()
		fmt.Fprintln(flag.CommandLine.Output(), "\nExample:")
		fmt.Fprintf(flag.CommandLine.Output(), "  %s --pull-id=123 --token=YOUR_TOKEN --repo-owner=owner --repo-name=repo diff.txt\n", os.Args[0])
	}

	flag.Parse()

	// Get the diff file from the positional arguments
	args := flag.Args()
	if len(args) < 1 {
		fmt.Println("Error: Missing diff file.")
		flag.Usage()
		os.Exit(1)
	}
	diffFile := args[0]

	// Check for required parameters
	if token == "" {
		fmt.Println("Error: Forgejo API token is not set. Use the --token flag or set FORGEJO_TOKEN environment variable.")
		flag.Usage()
		os.Exit(1)
	}

	if repoOwner == "" {
		fmt.Println("Error: Repository owner is not set. Use the --repo-owner flag or set REPO_OWNER environment variable.")
		flag.Usage()
		os.Exit(1)
	}

	if repoName == "" {
		fmt.Println("Error: Repository name is not set. Use the --repo-name flag or set REPO_NAME environment variable.")
		flag.Usage()
		os.Exit(1)
	}

	// Ensure that only one of issueId or pullId is set
	if (issueId == 0 && pullId == 0) || (issueId != 0 && pullId != 0) {
		fmt.Println("Error: You must specify either --issue-id or --pull-id, but not both.")
		flag.Usage()
		os.Exit(1)
	}

	// Determine which ID to use
	var itemId int
	var itemType string
	if issueId != 0 {
		itemId = issueId
		itemType = "issue"
	} else {
		itemId = pullId
		itemType = "pull"
	}

	// Read the diff file
	diffContentBytes, err := os.ReadFile(diffFile)
	if err != nil {
		fmt.Printf("Error reading diff file '%s': %v\n", diffFile, err)
		os.Exit(1)
	}

	// Prepare the comment content
	diffContent := string(diffContentBytes)
	commentBody := fmt.Sprintf("```diff\n%s\n```", diffContent)

	// Prepare the request payload
	payload := map[string]string{
		"body": commentBody,
	}
	payloadBytes, err := json.Marshal(payload)
	if err != nil {
		fmt.Printf("Error marshaling payload: %v\n", err)
		os.Exit(1)
	}

	// Construct the API URL
	apiURL := fmt.Sprintf("%s/repos/%s/%s/issues/%d/comments", forgejoAPIURL, repoOwner, repoName, itemId)

	// Create the HTTP request
	req, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(payloadBytes))
	if err != nil {
		fmt.Printf("Error creating request: %v\n", err)
		os.Exit(1)
	}

	req.Header.Set("Authorization", fmt.Sprintf("token %s", token))
	req.Header.Set("Content-Type", "application/json")

	// Send the request
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Printf("Error sending request: %v\n", err)
		os.Exit(1)
	}
	defer resp.Body.Close()

	// Read the response body
	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("Error reading response: %v\n", err)
		os.Exit(1)
	}

	// Check the response status code
	if resp.StatusCode != 201 {
		fmt.Printf("Failed to post comment. HTTP status: %d\n", resp.StatusCode)
		fmt.Printf("Response body: %s\n", string(respBody))
		os.Exit(1)
	} else {
		fmt.Printf("Posted diff to Forgejo %s #%d\n", itemType, itemId)
	}
}
