package vercel

import (
	"encoding/json"

	"github.com/pingcap/errors"
)

type VercelProject struct {
	VercelProjectID   string `form:"vercel_project_id" json:"vercel_project_id" binding:"required"`
	VercelProjectName string `form:"vercel_project_name" json:"vercel_project_name" binding:"required"`
}

type AddConnectionRequest struct {
	VercelProject
	VercelIntegrationConfiguration
	FrameworkType string `json:"framework_type" enums:"General,Prisma,TiDB Cloud Serverless Driver" binding:"required"`
	Database      string `json:"database"`
	BranchEnabled bool   `json:"branch_enabled"`
}

type VercelIntegrationConfiguration struct {
	ConfigurationID string `uri:"configuration_id" json:"configuration_id" binding:"required"`
}

type TiDBCluster struct {
	TiDBProject
	TiDBClusterID string `json:"tidb_cluster_id" uri:"cluster_id" binding:"required"`
}

type TiDBProject struct {
	TiDBOrgID     string `json:"tidb_org_id" uri:"org_id" binding:"required"`
	TiDBProjectID string `json:"tidb_project_id" uri:"project_id" binding:"required"`
}

type TiDBOrg struct {
	TiDBOrgID string `json:"tidb_org_id" uri:"org_id" binding:"required"`
}

type ClusterEnvironments struct {
	DBHost     string
	DBPort     int
	DBUser     string
	DBPassword string
	DBSslCa    []byte
	DBDatabase string
}

type ListConnectionResponse struct {
	Connections []TiDBVercelConnectionVO `json:"connections"`
	BaseResp
}

type TiDBProjectVercelConnection struct {
	TiDBClustersVercelConnection []TiDBTargetVercelConnectionVO `json:"connections_array"`
	BaseResp
}

type TiDBOrgVercelConnection struct {
	TiDBClustersVercelConnection []TiDBTargetVercelConnectionVO `json:"connections_array"`
	BaseResp
}

type TiDBTargetVercelConnectionVO struct {
	TiDBProject
	Projects        []VercelProject `json:"projects"`
	TiDBOrgName     string          `json:"tidb_org_name"`
	TiDBProjectName string          `json:"tidb_project_name"`
	ConnectionTarget
}

type TiDBVercelConnectionVO struct {
	TiDBProject
	VercelProject
	TiDBOrgName     string `json:"tidb_org_name"`
	TiDBProjectName string `json:"tidb_project_name"`
	ConnectionTarget
}

type ConnectionTarget struct {
	TargetType    ConnectionTargetType `json:"target_type"`
	TargetName    string               `json:"target_name"`
	TargetID      string               `json:"target_id"`
	BranchEnabled bool                 `json:"branch_enabled"`
}

type VercelEvent struct {
	ID        string      `json:"id"`
	Type      EventType   `json:"type"`
	CreatedAt int64       `json:"createdAt"`
	Payload   interface{} `json:"payload"`
}

func (d *VercelEvent) UnmarshalJSON(data []byte) error {
	var obj struct {
		ID        string    `json:"id"`
		Type      EventType `json:"type"`
		CreatedAt int64     `json:"createdAt"`
	}
	if err := json.Unmarshal(data, &obj); err != nil {
		return err
	}

	d.ID = obj.ID
	d.Type = obj.Type
	d.CreatedAt = obj.CreatedAt

	switch obj.Type {
	case ProjectRemovedDeprecated, ProjectRemoved:
		var py struct {
			ProjectEventPayload `json:"payload"`
		}
		err := json.Unmarshal(data, &py)
		if err != nil {
			return err
		}
		d.Payload = py.ProjectEventPayload
	case IntegrationRemovedDeprecated, IntegrationRemoved:
		var py struct {
			IntegrationEventPayload `json:"payload"`
		}
		err := json.Unmarshal(data, &py)
		if err != nil {
			return err
		}
		d.Payload = py.IntegrationEventPayload
	case DeploymentCreated, DeploymentReady, DeploymentError, DeploymentCanceled:
		var py struct {
			DeploymentPayload `json:"payload"`
		}
		err := json.Unmarshal(data, &py)
		if err != nil {
			return err
		}
		d.Payload = py.DeploymentPayload
	default:
		return errors.Errorf("Unsupported event type: %s", obj.Type)
	}

	return nil
}

type ProjectEventPayload struct {
	Project struct {
		ID   string `json:"id"`
		Name string `json:"name"`
	} `json:"project"`
}

type IntegrationEventPayload struct {
	Configuration struct {
		ID               string   `json:"id"`
		ProjectSelection string   `json:"projectSelection"`
		Projects         []string `json:"projects"`
	} `json:"configuration"`
}

type DeploymentPayload struct {
	Deployment struct {
		ID   string            `json:"id"`
		Meta map[string]string `json:"meta"`
		Name string            `json:"name"`
		URL  string            `json:"url"`
	} `json:"deployment"`
	Links struct {
		Deployment string `json:"deployment"`
		Project    string `json:"project"`
	} `json:"links"`
	Plan    string `json:"plan"`
	Project struct {
		ID string `json:"id"`
	} `json:"project"`
	Regions []string `json:"regions"`
	Target  *string  `json:"target"`
}

type IntegrationAccessTokenRequest struct {
	Code             string  `form:"code" json:"code" binding:"required" url:"-"`                               // The code received when adding integration.
	TeamID           *string `form:"teamId" json:"teamId" url:"teamId,omitempty"`                               // The ID of the team (only if a team is selected).
	ConfigurationID  *string `form:"configurationId" json:"configurationId" url:"configurationId,omitempty"`    // The configuration ID of the integration(absent with External installation).
	Next             *string `form:"next" json:"next" url:"next,omitempty"`                                     // The URL to redirect to after the integration has been installed(absent with External installation).
	CurrentProjectID *string `form:"currentProjectId" json:"currentProjectId" url:"currentProjectId,omitempty"` // The ID of the created project(only exist when installing via Deploy Button).
	ExternalID       *string `form:"external-id" json:"external-id" url:"external-id,omitempty"`                // An external ID or reference(only exist when installing via Deploy Button).
}

type ProjectVO struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

type RetrieveProjectResponse struct {
	Projects []ProjectVO `json:"projects"`
	BaseResp
}

type AccessTokenResponse struct {
	RedirectURL string `json:"redirectUrl"`
	BaseResp
}

type CreateClusterRequest struct {
	ClusterName      string   `json:"cluster_name" binding:"required"`
	ConfigurationID  string   `json:"configuration_id" binding:"required"`
	VercelProjectIDs []string `json:"selected_vercel_projects" binding:"required"`
}

type AddDataAppConnectionRequest struct {
	VercelProject
	VercelIntegrationConfiguration
}

type DataAppPath struct {
	TiDBProject
	DataAppID string `uri:"data_app_id" binding:"required"`
}

type DataAppEnvironments struct {
	DataAppBaseUrl    *string
	DataAppPublicKey  *string
	DataAppPrivateKey *string
}

type Resp struct {
	ErrorCode    int64  `json:"err_code"`
	ErrorMessage string `json:"err_msg"`
}

type BaseResp struct {
	BaseResp Resp `json:"base_resp"`
}

func NewBaseResp(code int64, message string) *BaseResp {
	return &BaseResp{
		BaseResp: Resp{
			ErrorCode:    code,
			ErrorMessage: message,
		},
	}
}

type MessageResp struct {
	Message string `json:"message"`
	BaseResp
}
