package domain

import (
	"strings"
	"time"

	"github.com/tidbcloud/dataflow-service/app/config"
	"github.com/tidbcloud/dataflow-service/app/repo/entity"
	"go.buf.build/protocolbuffers/go/linuxgit/tidbcloud/base"
	"google.golang.org/protobuf/types/known/timestamppb"
)

type Pager struct {
	Page     int64
	PageSize int64
}

type PagerOptionOp func(*Pager)

func NewPager(ops ...PagerOptionOp) *Pager {
	p := &Pager{
		Page:     config.DEFAULT_PAGE_NUMBER,
		PageSize: config.DEFAULT_PAGE_SIZE,
	}
	for _, op := range ops {
		op(p)
	}
	return p
}

func PagerOp(pager *base.Pager) PagerOptionOp {
	return func(p *Pager) {
		if pager == nil {
			return
		}
		PageNumberOp(pager.Page)(p)
		PageSizeOp(pager.PageSize)(p)
	}
}

func PageSizeOp(size int64) PagerOptionOp {
	return func(p *Pager) {
		if size > 0 {
			p.PageSize = size
		}
	}
}

func PageNumberOp(page int64) PagerOptionOp {
	return func(p *Pager) {
		if page > 0 {
			p.Page = page
		}
	}
}

func (p *Pager) CalculateOffsetAndLimit() (offset, limit int64) {
	page := p.Page
	pageSize := p.PageSize

	limit = p.PageSize
	if page > 0 {
		page = page - 1
	}
	offset = page * pageSize
	return offset, limit
}

type InfraProviderType string

const (
	InfraProviderTypeEKS   InfraProviderType = "eks"
	InfraProviderTypeGKE   InfraProviderType = "gke"
	InfraProviderTypeAKS   InfraProviderType = "aks"
	InfraProviderTypeACK   InfraProviderType = "ack"
	InfraProviderTypeAWS   InfraProviderType = "aws"
	InfraProviderTypeGCP   InfraProviderType = "gcp"
	InfraProviderTypeAzure InfraProviderType = "azure"
)

type CloudProviderType string

const (
	CloudProviderTypeAWS   CloudProviderType = "aws"
	CloudProviderTypeGCP   CloudProviderType = "gcp"
	CloudProviderTypeAzure CloudProviderType = "azure"
)

var CloudProviderTypeDescriptionMap = map[CloudProviderType]string{
	CloudProviderTypeAWS:   "Amazon Web Services",
	CloudProviderTypeGCP:   "Google Cloud Platform",
	CloudProviderTypeAzure: "Microsoft Azure",
}

func CloudProviderTypeDomain2Entity(cloudProviderType CloudProviderType) entity.CloudProviderType {
	switch cloudProviderType {
	case CloudProviderTypeAWS:
		return entity.CloudProviderTypeAWS
	case CloudProviderTypeGCP:
		return entity.CloudProviderTypeGCP
	case CloudProviderTypeAzure:
		return entity.CloudProviderTypeAzure
	default:
		return entity.CloudProviderType(cloudProviderType)
	}
}

func CloudProviderTypeEntity2Domain(cloudProviderType entity.CloudProviderType) CloudProviderType {
	switch cloudProviderType {
	case entity.CloudProviderTypeAWS:
		return CloudProviderTypeAWS
	case entity.CloudProviderTypeGCP:
		return CloudProviderTypeGCP
	case entity.CloudProviderTypeAzure:
		return CloudProviderTypeAzure
	default:
		return CloudProviderType(cloudProviderType)
	}
}

func InfraProviderType2CloudProviderType[T string | InfraProviderType](infraProviderType T) CloudProviderType {
	switch InfraProviderType(infraProviderType) {
	case InfraProviderTypeAWS, InfraProviderTypeEKS:
		return CloudProviderTypeAWS
	case InfraProviderTypeGCP, InfraProviderTypeGKE:
		return CloudProviderTypeGCP
	case InfraProviderTypeAzure, InfraProviderTypeAKS:
		return CloudProviderTypeAzure
	default:
		return ""
	}
}

func NewTimestamp(t *time.Time) *timestamppb.Timestamp {
	if t == nil || t.IsZero() {
		return nil
	}
	return timestamppb.New(*t)
}

// CloudProviderToInfraType maps cloud provider name ("aws","gcp","azure") to the
// infra-platform type string expected by RegionalNetworkReq and switch statements.
func CloudProviderToInfraType[T string | CloudProviderType](cloudProvider T) InfraProviderType {
	switch strings.ToLower(string(cloudProvider)) {
	case string(CloudProviderTypeAWS):
		return InfraProviderTypeEKS
	case string(CloudProviderTypeGCP):
		return InfraProviderTypeGKE
	case string(CloudProviderTypeAzure):
		return InfraProviderTypeAKS
	default:
		return InfraProviderType(cloudProvider)
	}
}
