//go:generate ${GOBIN}/mockgen -destination devops_mock.go -package=devops ${GO_MODULE}/pkg/clients/devops Interface
package devops

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"
)

type Interface interface {
	CreateAnalysis(issueID string) (string, error)
	GetClusterIDForStTicket(issueID string) (string, error)
}

type DevOpsClient struct {
	client     *http.Client
	devOpsAddr string
	apiKey     string
}

func New(addr string, apiKey string) (Interface, error) {
	httpCli := &http.Client{Timeout: 30 * time.Second}
	return &DevOpsClient{
		client:     httpCli,
		devOpsAddr: addr,
		apiKey:     apiKey,
	}, nil
}

type CreateAnalysisResp struct {
	AnalysisUUID string `json:"analysis_uuid"`
}

type JiraIntegration struct {
	Enabled                   bool `json:"enabled"`
	PostInsightAsComment      bool `json:"post_insight_as_comment"`
	UploadPackageAsAttachment bool `json:"upload_package_as_attachment"`
}

type CreateAnalysisReq struct {
	JiraIssueID     string          `json:"jira_issue_id"`
	JiraIntegration JiraIntegration `json:"jira_integration"`
}

type GetClusterIDResp struct {
	ClusterID string `json:"cluster_id"`
}

func (c *DevOpsClient) CreateAnalysis(issueID string) (string, error) {
	uploadPackageAsAttachment := false
	if strings.HasPrefix(issueID, "O11Y") {
		uploadPackageAsAttachment = true
	}
	body := CreateAnalysisReq{
		JiraIssueID: issueID,
		JiraIntegration: JiraIntegration{
			Enabled:                   true,
			PostInsightAsComment:      true,
			UploadPackageAsAttachment: uploadPackageAsAttachment,
		},
	}
	bodyBytes, err := json.Marshal(body)
	if err != nil {
		return "", fmt.Errorf("fail to marshal request body, %w", err)
	}
	req, _ := http.NewRequest("POST",
		fmt.Sprintf("%s/api/v1/devops/aiops/proxy/api/v1/aiops/guardian/analyses", c.devOpsAddr),
		bytes.NewReader(bodyBytes))
	req.Header.Add("X-API-Key", c.apiKey)

	res, err := c.client.Do(req)
	if err != nil {
		return "", fmt.Errorf("fail to create guardian analysis, %w", err)
	}
	defer res.Body.Close()

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

	if res.StatusCode != http.StatusOK {
		return "", fmt.Errorf("fail to create guardian analysis, status code: %d, message: %s", res.StatusCode, string(resBody))
	}

	var structRes CreateAnalysisResp
	err = json.Unmarshal(resBody, &structRes)
	if err != nil {
		return "", fmt.Errorf("fail to unmarshal response body, %w", err)
	}
	return structRes.AnalysisUUID, nil
}

func (c *DevOpsClient) GetClusterIDForStTicket(issueID string) (string, error) {
	req, _ := http.NewRequest("GET",
		fmt.Sprintf("%s/api/v1/devops/aiops/proxy/api/v1/aiops/guardian/st_cluster_id?jira_issue_id=%s", c.devOpsAddr, issueID),
		nil)
	req.Header.Add("X-API-Key", c.apiKey)

	res, err := c.client.Do(req)
	if err != nil {
		return "", fmt.Errorf("fail to get cluster id, %w", err)
	}
	defer res.Body.Close()

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

	if res.StatusCode != http.StatusOK {
		return "", fmt.Errorf("fail to get cluster id, status code: %d, message: %s", res.StatusCode, string(resBody))
	}

	var structRes GetClusterIDResp
	err = json.Unmarshal(resBody, &structRes)
	if err != nil {
		return "", fmt.Errorf("fail to unmarshal response body, %w", err)
	}
	return structRes.ClusterID, nil
}
