package clinic

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"time"

	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"

	"gorm.io/gorm"
)

type ActivityResp struct {
	Status string      `json:"status"`
	Result []*Activity `json:"result"`
}

type Activity struct {
	Type            string            `json:"type"`
	Name            string            `json:"name"`
	DisplayName     string            `json:"display_name"`
	Catalog         string            `json:"catalog"`
	Severity        int               `json:"severity"`
	ActivityID      string            `json:"activity_id"`
	ApplicationID   string            `json:"application_id"`
	ConceptID       string            `json:"concept_id"`
	TargetID        string            `json:"target_id"`
	CalibrationTime int64             `json:"calibration_time"`
	Source          string            `json:"source"`
	Author          string            `json:"author"`
	ContextID       string            `json:"context_id"`
	Context         []string          `json:"context"`
	Tags            map[string]string `json:"tags,omitempty"`
	Payload         any               `json:"payload"`
}

type ActivityTags struct {
	Status string `json:"status"`
}

type ClusterResp struct {
	Total uint          `json:"total"`
	Items []ClusterItem `json:"items"`
}

type ClusterItem struct {
	TenantID    string `json:"tenantID"`
	ClusterName string `json:"clusterName"`
}

type Client struct {
	client         *http.Client
	regionDB       *gorm.DB
	clinicInfoAddr string
	authString     string
	eventURL       string
	eventSource    string
	eventKey       string
	logger         log.Logger
}

// create clinic client.
func New(
	regionDB *gorm.DB,
	addr string,
	auth string,
	logger log.Logger,
	eventURL string,
	eventSource string,
	eventKey string,
) (*Client, error) {
	httpCli := &http.Client{Timeout: 10 * time.Second}
	return &Client{
		client:         httpCli,
		regionDB:       regionDB,
		clinicInfoAddr: addr,
		authString:     auth,
		logger:         logger,
		eventURL:       eventURL,
		eventSource:    eventSource,
		eventKey:       eventKey,
	}, nil
}

func (cc *Client) GetKindNClusterNameByTenantIDAndClusterID(tenantID string, clusterID string) (string, string, error) {
	const selectKindByTenantID = `
	SELECT 
		kind
	FROM devops_prod.tenants where id = ?;`

	// search by tenant
	var tmpID string
	var clusterName string
	if clusterID != `` {
		url := cc.clinicInfoAddr + clusterID
		fmt.Println("request url", url)
		req, _ := http.NewRequest("GET", url, nil)

		req.Header.Add("Authorization", "Bearer "+cc.authString)

		var structRes ClusterResp
		res, err := cc.client.Do(req)
		if err != nil {
			return "", "", err
		}
		defer res.Body.Close()

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

		err = json.Unmarshal(resBody, &structRes)
		if err != nil {
			return "", "", err
		}
		fmt.Println("resp", structRes)
		if len(structRes.Items) > 0 {
			tmpID = structRes.Items[0].TenantID
			clusterName = structRes.Items[0].ClusterName

		}
	}
	if tenantID != `` {
		tmpID = tenantID
	}
	tenantInt, err := strconv.ParseUint(tmpID, 10, 64)
	if err != nil {
		return clusterName, ``, err
	}
	var kind string
	res := cc.regionDB.Raw(selectKindByTenantID, tenantInt).Scan(&kind)
	return clusterName, kind, CheckGORMErr(res)
}

func CheckGORMErr(result *gorm.DB) error {
	err := result.Error
	if err == nil && result.RowsAffected == 0 {
		err = gorm.ErrRecordNotFound
	}
	return err
}

func (cc *Client) GetActivities(from int, to int, clusterID string) ([]*Activity, error) {
	req, _ := http.NewRequest("GET",
		fmt.Sprintf("%s%s/from/%s/to/%s", cc.eventURL, clusterID, strconv.Itoa(from), strconv.Itoa(to)),
		nil)
	req.Header.Add("x-activityhub-source", cc.eventSource)
	req.Header.Add("x-activityhub-key", cc.eventKey)

	var structRes ActivityResp

	res, err := cc.client.Do(req)
	if err != nil {
		level.Error(cc.logger).Log(err, "fail to get activities", "cluster id", clusterID)
		return nil, err
	}
	defer res.Body.Close()

	resBody, err := io.ReadAll(res.Body)
	if err != nil {
		level.Error(cc.logger).Log(err, "fail to read body")
		return nil, err
	}

	err = json.Unmarshal(resBody, &structRes)
	if err != nil {
		level.Error(cc.logger).Log(err, "fail to unmarshal result")
		return nil, err
	}

	return structRes.Result, nil
}

func (cc *Client) InsertAlertIntoTables(project string, rawData []byte) error {
	const insertSQL = `
	INSERT INTO jiralert_dev.cached_issues (project, rawdata)
		VALUES (?, ?)`

	result := cc.regionDB.Exec(insertSQL, project, rawData)
	return CheckGORMErr(result)
}
