package gitea

import (
	"fmt"
	"net/url"
	"path"
	"strings"
	"time"

	"github.com/valyala/fasthttp"
	"github.com/valyala/fastjson"

	"codeberg.org/codeberg/pages/server/shared"
)

const giteaAPIRepos = "/api/v1/repos/"

type Client struct {
	giteaRoot     string
	giteaAPIToken string
}

type FileResponse struct {
	Exists   bool
	MimeType string
	Body     []byte
}

func (f FileResponse) IsEmpty() bool { return len(f.Body) != 0 }

func NewClient(giteaRoot, giteaAPIToken string) *Client {
	return &Client{
		giteaRoot:     giteaRoot,
		giteaAPIToken: giteaAPIToken,
	}
}

// TODOs:
// * own client to store token & giteaRoot
// * handle 404 -> page will show 500 atm

func (client *Client) GiteaRawContent(targetOwner, targetRepo, ref, resource string) ([]byte, error) {
	req := fasthttp.AcquireRequest()

	req.SetRequestURI(path.Join(client.giteaRoot, giteaAPIRepos, targetOwner, targetRepo, "raw", resource+"?ref="+url.QueryEscape(ref)))
	req.Header.Set(fasthttp.HeaderAuthorization, client.giteaAPIToken)
	res := fasthttp.AcquireResponse()

	if err := shared.GetFastHTTPClient(10*time.Second).Do(req, res); err != nil {
		return nil, err
	}
	if res.StatusCode() != fasthttp.StatusOK {
		return nil, fmt.Errorf("unexpected status code '%d'", res.StatusCode())
	}
	return res.Body(), nil
}

func (client *Client) ServeRawContent(uri string) (*fasthttp.Response, error) {
	fastClient := shared.GetFastHTTPClient(10 * time.Second)

	req := fasthttp.AcquireRequest()
	req.SetRequestURI(path.Join(client.giteaRoot, giteaAPIRepos, uri))
	req.Header.Set(fasthttp.HeaderAuthorization, client.giteaAPIToken)

	resp := fasthttp.AcquireResponse()
	resp.SetBodyStream(&strings.Reader{}, -1)

	return resp, fastClient.Do(req, resp)
}

func (client *Client) GiteaGetRepoBranchTimestamp(repoOwner, repoName, branchName string) (time.Time, error) {
	fastClient := shared.GetFastHTTPClient(5 * time.Second)

	req := fasthttp.AcquireRequest()
	req.SetRequestURI(path.Join(client.giteaRoot, giteaAPIRepos, repoOwner, repoName, "branches", branchName))
	req.Header.Set(fasthttp.HeaderAuthorization, client.giteaAPIToken)
	res := fasthttp.AcquireResponse()

	if err := fastClient.Do(req, res); err != nil {
		return time.Time{}, err
	}
	if res.StatusCode() != fasthttp.StatusOK {
		return time.Time{}, fmt.Errorf("unexpected status code '%d'", res.StatusCode())
	}
	return time.Parse(time.RFC3339, fastjson.GetString(res.Body(), "commit", "timestamp"))
}

func (client *Client) GiteaGetRepoDefaultBranch(repoOwner, repoName string) (string, error) {
	fastClient := shared.GetFastHTTPClient(5 * time.Second)

	req := fasthttp.AcquireRequest()
	req.SetRequestURI(path.Join(client.giteaRoot, giteaAPIRepos, repoOwner, repoName))
	req.Header.Set(fasthttp.HeaderAuthorization, client.giteaAPIToken)
	res := fasthttp.AcquireResponse()

	if err := fastClient.Do(req, res); err != nil {
		return "", err
	}
	if res.StatusCode() != fasthttp.StatusOK {
		return "", fmt.Errorf("unexpected status code '%d'", res.StatusCode())
	}
	return fastjson.GetString(res.Body(), "default_branch"), nil
}