package fadcli

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"regexp"
	"strconv"
	"strings"

	relent "github.com/tidbcloud/devops/entity/release"
)

func (c *client) storePRLink(link string) error {
	const endpoint = "https://us-west-2.data.tidbcloud.com/api/v1beta/app/dataapp-WObJIvhw/endpoint/approved_prs"
	req, err := http.NewRequest(http.MethodPost, endpoint, strings.NewReader(fmt.Sprintf(`{"pr_link": "%s"}`, link)))
	if err != nil {
		return err
	}
	req.SetBasicAuth(c.DSPublicKey, c.DSPrivateKey)
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}

	respContent, err := io.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	var dsResp struct {
		Data struct {
			Result struct {
				Code int `json:"code"`
			} `json:"result"`
		} `json:"data"`
	}
	err = json.Unmarshal(respContent, &dsResp)
	if err != nil {
		return err
	}

	if dsResp.Data.Result.Code != 200 {
		return fmt.Errorf("data service returns non 200: code %d", dsResp.Data.Result.Code)
	}
	return nil
}

func (c *client) rerunCheckForPR(pr *relent.GithubPR) error {
	runID, err := c.getCheckRunID(pr)
	if err != nil {
		return err
	}
	// in case no such check workflow
	if runID == 0 {
		return nil
	}
	url := fmt.Sprintf("https://api.github.com/repos/tidbcloud/app-delivery/actions/runs/%d/rerun", runID)

	req, err := http.NewRequest(http.MethodPost, url, nil)
	if err != nil {
		return err
	}
	req.Header.Set("Authorization", "Bearer "+c.GithubToken)
	req.Header.Set("Accept", "application/vnd.github+json")
	req.Header.Set("X-GitHub-Api-Version", "2022-11-28")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}

	if resp.StatusCode != 201 {
		return fmt.Errorf("rerun check workflow failed: %s", resp.Status)
	}
	return nil
}

func (c *client) getPRHeadRefName(pr *relent.GithubPR) (string, error) {
	url := fmt.Sprintf("https://api.github.com/repos/%s/%s/pulls/%d", pr.RepoOwner, pr.RepoName, pr.PRNumber)
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return "", err
	}
	req.Header.Set("Authorization", "Bearer "+c.GithubToken)
	req.Header.Set("Accept", "application/vnd.github+json")
	req.Header.Set("X-GitHub-Api-Version", "2022-11-28")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}

	respContent, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	var gitResp struct {
		Head struct {
			Ref string `json:"ref"`
		} `json:"head"`
	}
	err = json.Unmarshal(respContent, &gitResp)
	if err != nil {
		return "", err
	}

	return gitResp.Head.Ref, nil
}

func (c *client) getCheckRunID(pr *relent.GithubPR) (int64, error) {
	headRef, err := c.getPRHeadRefName(pr)
	if err != nil {
		return 0, err
	}

	url := fmt.Sprintf("https://api.github.com/repos/%s/%s/commits/%s/check-runs", pr.RepoOwner, pr.RepoName, headRef)
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return 0, err
	}
	req.Header.Set("Authorization", "Bearer "+c.GithubToken)
	req.Header.Set("Accept", "application/vnd.github+json")
	req.Header.Set("X-GitHub-Api-Version", "2022-11-28")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return 0, err
	}

	respContent, err := io.ReadAll(resp.Body)
	if err != nil {
		return 0, err
	}

	var gitResp struct {
		CheckRuns []struct {
			Name    string `json:"name"`
			HtmlUrl string `json:"html_url"`
		} `json:"check_runs"`
	}
	err = json.Unmarshal(respContent, &gitResp)
	if err != nil {
		return 0, err
	}

	for _, run := range gitResp.CheckRuns {
		if run.Name == "check-if-can-be-merged" {
			r, _ := regexp.Compile("/runs/([0-9]+)/job")
			xs := r.FindStringSubmatch(run.HtmlUrl)
			if len(xs) != 2 {
				return 0, fmt.Errorf("unexpected check run url: %s", run.HtmlUrl)
			}
			return strconv.ParseInt(xs[1], 10, 64)
		}
	}

	// in case `check-if-can-be-merged` not applied in this PR
	return 0, nil
}
