package message

import (
	"context"

	prometheusv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
	"github.com/tidbcloud/observability/pkg/common/constants"
	"github.com/tidbcloud/observability/pkg/common/structs"
)

type OpenCommonHeaders struct {
	Vendor  constants.ProvidedVendor `header:"x-vendor" validate:"required,oneof=aws gcp azure alicloud"`
	Region  string                   `header:"x-region" validate:"required"`
	OrgID   string                   `header:"x-org-id" validate:"required"`
	UserID  string                   `header:"x-user-id"`
	BizType string                   `header:"x-biz-type"`
}

type OpenMetricsConfig struct {
	Status        constants.ObservabilityCategoryStatus `json:"status"`
	DataRetention int                                   `json:"dataRetention"`
	QueryEndpoint string                                `json:"queryEndpoint"`
}

type OpenLogsConfig struct {
	Status        constants.ObservabilityCategoryStatus `json:"status"`
	DataRetention int                                   `json:"dataRetention"`
}

type OpenAlertConfig struct {
	Status         constants.ObservabilityCategoryStatus `json:"status"`
	RuleTemplateID string                                `json:"ruleTemplateID"`
}

type OpenObservabilityCluster struct {
	ID                  string                   `json:"id"`
	Vendor              constants.ProvidedVendor `json:"vendor"`
	Region              string                   `json:"region"`
	BizType             string                   `json:"bizType"`
	TenantID            string                   `json:"tenantID"`
	ProjectID           string                   `json:"projectID"`
	ApplicationID       string                   `json:"applicationID"`
	RuleTemplateID      string                   `json:"ruleTemplateID,omitempty"`
	Tags                []string                 `json:"tags,omitempty"`
	ShareMode           constants.ShareMode      `json:"share_mode"`
	Note                string                   `json:"note,omitempty"`
	Status              constants.ResourceStatus `json:"status,omitempty"`
	Metrics             *OpenMetricsConfig       `json:"metrics,omitempty"`
	Logs                *OpenLogsConfig          `json:"logs,omitempty"`
	Alerts              *OpenAlertConfig         `json:"alerts,omitempty"`
	EndpointServiceName string                   `json:"endpointServiceName,omitempty"`
	DNSName             string                   `json:"dnsName,omitempty"`
	AgentRoleARN        string                   `json:"agentRoleARN,omitempty"`
}

type OpenCreateClusterRequest struct {
	ProjectID       string              `json:"projectID" validate:"required"`
	ApplicationID   string              `json:"applicationID" validate:"required"`
	ShareMode       constants.ShareMode `json:"shareMode,omitempty"`
	Note            string              `json:"note,omitempty"`
	Tags            []string            `json:"tags,omitempty"`
	AgentAccessARN  string              `json:"agentAccessARN" validate:"required"`
	AgentManagerARN string              `json:"agentManagerARN" validate:"required"`
	RuleTemplateID  string              `json:"ruleTemplateID,omitempty"`
}

type OpenClusterListReq struct {
	ProjectID     string `json:"projectID" form:"projectID"`
	ApplicationID string `json:"applicationID" form:"applicationID"`
}

type OpenClusterListResponse struct {
	Clusters      []OpenObservabilityCluster `json:"clusters"`
	NextPageToken string                     `json:"next_page_token,omitempty"`
}

type OpenDeleteClusterReq struct {
	ID             string `json:"id" swaggerignore:"true"`
	AgentAccessARN string `json:"agentAccessARN" form:"agentAccessARN"`
}

type OpenDetailClusterReq struct {
	ID string `json:"id" swaggerignore:"true"`
}

type OpenPauseClusterReq struct {
	ID string `json:"id" swaggerignore:"true"`
}

type OpenResumeClusterReq struct {
	ID string `json:"id" swaggerignore:"true"`
}

type OpenModuleConfigRequest struct {
	Retention int `json:"retention" validate:"required"`
}

type OpenModuleStatusRequest struct {
	Status string `json:"status" validate:"required,oneof=enabled disabled"`
}

type OpenAlertRuleTemplate struct {
	ID   string `json:"id"`
	Desc string `json:"desc"`
}

type OpenAlertRuleTemplateList struct {
	Templates []OpenAlertRuleTemplate `json:"templates"`
}

type OpenAlertRule struct {
	prometheusv1.PrometheusRuleSpec
}

type OpenUpdateAlertRuleReq struct {
	ID         string        `json:"id" swaggerignore:"true"`
	AlertRules OpenAlertRule `json:"alertRules"`
}

func OpenConvertCluster(ctx context.Context, src structs.ObservabilityCluster) OpenObservabilityCluster {
	dst := OpenObservabilityCluster{
		ID:     src.ID,
		Vendor: src.ClusterBaseInfo.Vendor,
		Region: src.Region,

		BizType:       src.BizType,
		TenantID:      src.TenantID,
		ProjectID:     src.ProjectID,
		ApplicationID: src.ApplicationID,

		RuleTemplateID: src.AlertInfo.RuleTemplateID,
		Tags:           src.Tags,
		ShareMode:      src.ShareMode,
		Note:           src.Note,
		Status:         src.Status,

		EndpointServiceName: src.MonitorInfo.EndpointServiceName,
		DNSName:             src.MonitorInfo.DNSName,
		AgentRoleARN:        src.AgentInfo.RoleARN,
	}

	dst.Metrics = &OpenMetricsConfig{
		Status:        constants.ObservabilityCategoryEnabled,
		DataRetention: constants.DefaultMetricsDataRetention,
		QueryEndpoint: src.OpenReadUri,
	}

	dst.Logs = &OpenLogsConfig{
		Status:        constants.ObservabilityCategoryEnabled,
		DataRetention: constants.DefaultLogsDataRetention,
	}

	dst.Alerts = &OpenAlertConfig{
		RuleTemplateID: src.AlertInfo.RuleTemplateID,
		Status:         constants.ObservabilityCategoryEnabled,
	}
	return dst
}

func OpenConvertClusterBaseInfo(ctx context.Context, src structs.ClusterBaseInfo) OpenObservabilityCluster {
	dst := OpenObservabilityCluster{
		ID:     src.ID,
		Vendor: src.Vendor,
		Region: src.Region,

		BizType:       src.BizType,
		TenantID:      src.TenantID,
		ProjectID:     src.ProjectID,
		ApplicationID: src.ApplicationID,

		Tags:      src.Tags,
		ShareMode: src.ShareMode,
		Note:      src.Note,
	}
	return dst
}

func OpenConvertClusters(ctx context.Context, src QueryClustersResp) OpenClusterListResponse {
	var dist OpenClusterListResponse
	for _, c := range src.Clusters {
		dist.Clusters = append(dist.Clusters, OpenConvertClusterBaseInfo(ctx, c))
	}
	return dist
}

func OpenConvertCreateReq(ctx context.Context, src OpenCreateClusterRequest, headers OpenCommonHeaders) CreateClusterReq {
	shareMode := src.ShareMode
	if len(shareMode) == 0 {
		shareMode = constants.SHARED
	}
	dist := CreateClusterReq{
		ClusterBaseInfo: structs.ClusterBaseInfo{
			CommonReqInfo: structs.CommonReqInfo{
				Vendor: headers.Vendor,
				Region: headers.Region,
			},
			BizType:       headers.BizType,
			TenantID:      headers.OrgID,
			ProjectID:     src.ProjectID,
			ApplicationID: src.ApplicationID,

			Tags:      src.Tags,
			ShareMode: shareMode,
			Note:      src.Note,
		},
		AgentManagerARN: src.AgentManagerARN,
		AgentAccessARN:  src.AgentAccessARN,
		RuleTemplateID:  src.RuleTemplateID,
	}

	return dist
}

func OpenConvertListReq(ctx context.Context, src OpenClusterListReq, headers OpenCommonHeaders) QueryClustersReq {
	dist := QueryClustersReq{
		CommonReqInfo: structs.CommonReqInfo{
			Vendor: headers.Vendor,
			Region: headers.Region,
		},
		BizType:       headers.BizType,
		TenantID:      headers.OrgID,
		ProjectID:     src.ProjectID,
		ApplicationID: src.ApplicationID,
	}
	return dist
}

func OpenConvertDetailReq(ctx context.Context, src OpenDetailClusterReq, headers OpenCommonHeaders) DetailClusterReq {
	dist := DetailClusterReq{
		CommonReqInfo: structs.CommonReqInfo{
			Vendor: headers.Vendor,
			Region: headers.Region,
		},
		ID: src.ID,
	}
	return dist
}

func OpenConvertDeleteReq(ctx context.Context, src OpenDeleteClusterReq, headers OpenCommonHeaders) DeleteClusterReq {
	dist := DeleteClusterReq{
		CommonReqInfo: structs.CommonReqInfo{
			Vendor: headers.Vendor,
			Region: headers.Region,
		},
		ID:             src.ID,
		AgentAccessARN: src.AgentAccessARN,
	}
	return dist
}

func OpenConvertPauseReq(ctx context.Context, src OpenPauseClusterReq, headers OpenCommonHeaders) PauseClusterReq {
	dist := PauseClusterReq{
		CommonReqInfo: structs.CommonReqInfo{
			Vendor: headers.Vendor,
			Region: headers.Region,
		},
		ID: src.ID,
	}
	return dist
}

func OpenConvertResumeReq(ctx context.Context, src OpenResumeClusterReq, headers OpenCommonHeaders) ResumeClusterReq {
	dist := ResumeClusterReq{
		CommonReqInfo: structs.CommonReqInfo{
			Vendor: headers.Vendor,
			Region: headers.Region,
		},
		ID: src.ID,
	}
	return dist
}
