package dto

import (
	"dataservices/commons/config"
	"dataservices/commons/utils"
	"dataservices/internal/entity"
	"time"

	"github.com/golang-jwt/jwt/v4"
	"github.com/tidbcloud/tiinf/errs"
)

// @Time    : 2022/12/12 4:03 PM
// @Author  : lvhongmeng

type GetDataAppRes struct {
	BasicRes
	Data *entity.DataApp `json:"data"`
}

type ListDataAppRes struct {
	BasicRes
	Data []*DataAppInfo `json:"data"`
}

type DataAppInfo struct {
	ID               uint64                 `json:"id"`
	OrgId            string                 `json:"org_id"`
	ProjectId        string                 `json:"project_id"`
	ExternalAppID    string                 `json:"external_app_id"`
	AppName          string                 `json:"app_name"`
	AppType          entity.DataAppType     `json:"app_type"`
	DeploymentRegion string                 `json:"deployment_region"`
	CreatedBy        string                 `json:"created_by"`
	UpdatedBy        string                 `json:"updated_by"`
	CreatedAt        utils.JsonTime         `json:"created_at"`
	UpdatedAt        utils.JsonTime         `json:"updated_at"`
	Endpoints        []EndpointSummary      `json:"endpoints,omitempty"`
	BaseUrl          string                 `json:"base_url"`
	AppVersion       string                 `json:"app_version"`
	Description      string                 `json:"description"`
	OasAuthorized    bool                   `json:"oas_authorized"`
	Status           string                 `json:"status"` // dataapp current status: normal,initializing
	OpenApiLink      string                 `json:"open_api_link,omitempty"`
	ApikeyMaxRPM     int                    `json:"apikey_max_rpm,omitempty"`
	Settings         entity.DataAppSettings `json:"settings"`
}

type CreateDataAppRes struct {
	BasicRes
	Data *CreateDataAppOut `json:"data"`
}

type CreateDataAppOut struct {
	AppInfo  *DataAppInfo     `json:"app_info"`
	Endpoint *EndpointSummary `json:"endpoint"`
}

type SyncDataToDDBReq struct {
	Tables []SyncTable `json:"tables"`
}
type SyncTable struct {
	TableName string   `json:"table_name"`
	IDs       []uint64 `json:"ids"`
}

type SyncDataToDDBResp struct {
	Tables []SyncTableRes `json:"tables"`
}
type SyncTableRes struct {
	TableName string `json:"table_name"`
	Count     int    `json:"count"`
	Error     error  `json:"error"`
}
type OKType struct {
	Status string `json:"status" example:"ok"`
}

type DataappPostmanCollection struct {
	Info struct {
		Name        string `json:"name"`
		Schema      string `json:"schema"`
		Description string `json:"description"`
	} `json:"info"`
	Item []DataappPostmanCollectionFolder `json:"item"`
	Auth struct {
		Type   string              `json:"type"`
		Digest []DataappPostmanVal `json:"digest"`
	} `json:"auth"`
	Variable []DataappPostmanVal `json:"variable"`
}

type DataappPostmanCollectionFolder struct {
	Name string               `json:"name"`
	Item []*DataappPostmanAPI `json:"item"`
}

type DataappPostmanAPI struct {
	Name                    string `json:"name"`
	ProtocolProfileBehavior struct {
		FollowAuthorizationHeader bool `json:"followAuthorizationHeader"`
		FollowRedirects           bool `json:"followRedirects"`
		FollowOriginalHttpMethod  bool `json:"followOriginalHttpMethod"`
	} `json:"protocolProfileBehavior"`
	Request struct {
		Method string              `json:"method"`
		Header []DataappPostmanVal `json:"header,omitempty"`
		Body   *DataappPostmanBody `json:"body,omitempty"`
		Url    string              `json:"url"`
	} `json:"request"`
}

type DataappPostmanBody struct {
	Mode    string                 `json:"mode"`
	Raw     string                 `json:"raw"`
	Options map[string]interface{} `json:"options"`
}

type DataappPostmanVal struct {
	Key   string `json:"key"`
	Value string `json:"value"`
	Type  string `json:"type"`
}

type DataappJWTClaims struct {
	jwt.RegisteredClaims
	AppID   string `json:"appid"`
	Creater string `json:"creater"`
	Sence   string `json:"sence"`
}

type JWTOption func(*DataappJWTClaims)

func WithJWTExpire(expire time.Duration) JWTOption {
	return func(c *DataappJWTClaims) {
		c.ExpiresAt = jwt.NewNumericDate(time.Now().Add(expire))
	}
}

func (c *DataappJWTClaims) GenerateJWT(opts ...JWTOption) (string, error) {
	if c == nil {
		return "", errs.NewBadRequest("invalid jwt claims", nil)
	}
	for _, opt := range opts {
		opt(c)
	}
	jwtSecretKey := config.Global().DataappConf.JwtSecretKey
	// c.ExpiresAt = jwt.NewNumericDate(time.Now().Add(12 * time.Hour))
	// c.ExpiresAt = jwt.NewNumericDate(time.Now().Add(1 * time.Minute))
	// c.IssuedAt = jwt.NewNumericDate(time.Now())
	// c.NotBefore = jwt.NewNumericDate(time.Now())
	t := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
	s, err := t.SignedString([]byte(jwtSecretKey))
	return s, err
}

// parse JWT
func (c *DataappJWTClaims) ParseJwt(s string) error {
	jwtSecretKey := config.Global().DataappConf.JwtSecretKey
	t, err := jwt.ParseWithClaims(s, c, func(token *jwt.Token) (interface{}, error) {
		return []byte(jwtSecretKey), nil
	})
	if err != nil {
		return errs.NewBadRequest("failed to parse jwt string", err)
	}

	_, ok := t.Claims.(*DataappJWTClaims)
	if !ok || !t.Valid {
		return errs.NewBadRequest("invalid jwt string", nil)
	}
	return nil
}

type DataappExportLinkRes struct {
	BasicRes
	Data string `json:"data"`
}

type CheckPostmanStatusRes struct {
	BasicRes
	Data bool `json:"data"`
}

type CheckSampleStatusRes struct {
	BasicRes
	Data struct {
		AppStatus   string                        `json:"app_status"` // dataapp current status: normal,initializing
		TaskRecords []entity.SampleDataTaskRecord `json:"task_records"`
	} `json:"data"`
}

type BatchGetCodeExampleRes struct {
	BasicRes
	Data struct {
		EndpointExamples []EndpointCodeExample `json:"endpoint_examples"`
	} `json:"data"`
}

type EndpointCodeExample struct {
	Path     string        `json:"path"`
	Method   string        `json:"method"`
	Examples []CodeExample `json:"examples"`
}

type GetSystemEndpointConfigResp struct {
	BasicRes
	Data *SystemEndpointConfigData `json:"data"`
}

type SystemEndpointConfigData struct {
	DataEndpoints []*EndpointConfig `json:"data_endpoints"`
}

type EndpointConfig struct {
	Type      string `json:"type"`
	Key       string `json:"key" binding:"required"`
	IsEnabled bool   `json:"is_enabled"`
}
