package gke

import (
	"context"
	"fmt"
	"time"

	"github.com/tidbcloud/infra-provider/pkg/cloud/gcp"
	"github.com/tidbcloud/infra-provider/pkg/deploy"
	"github.com/tidbcloud/infra-provider/pkg/util"
	"github.com/tidbcloud/infra-provider/regional-server/api/v1alpha1"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/controllers/appbox/task"
)

const (
	serviceAccountPrefix = "serviceAccount:"
	roleLoggingWriter    = "roles/logging.logWriter"
	roleMonitoringWriter = "roles/monitoring.metricWriter"
	// Cluster-agent needs this to restart gke nodes.
	roleInstanceAdmin = "roles/compute.instanceAdmin"
)

type ProjectPolicy struct {
	*task.BaseTask
	gcpCli gcp.Client
}

func NewProjectPolicy(ctx *task.Context, c gcp.Client) *ProjectPolicy {
	return &ProjectPolicy{
		BaseTask: &task.BaseTask{Context: ctx},
		gcpCli:   c,
	}
}

func (t *ProjectPolicy) Name() string {
	return "ProjectPolicy"
}

func (t *ProjectPolicy) Create(ctx context.Context) deploy.Result {
	t.BeginAt = util.Pointer(time.Now())
	if t.APPBox.Labels[v1alpha1.IsLegacyKey] == "true" {
		return deploy.Done()
	}
	saEmail := t.APPBox.Status.IAM.ServiceAccountEmail
	if saEmail == "" {
		return deploy.Error(fmt.Errorf("service account is empty"))
	}

	if err := t.gcpCli.ResourceManager().AddProjectPolicyBinding(
		ctx,
		t.ProjectID(),
		roleLoggingWriter,
		serviceAccountPrefix+saEmail,
	); err != nil {
		return deploy.Error(err)
	}

	if err := t.gcpCli.ResourceManager().AddProjectPolicyBinding(
		ctx,
		t.ProjectID(),
		roleMonitoringWriter,
		serviceAccountPrefix+saEmail,
	); err != nil {
		return deploy.Error(err)
	}

	if err := t.gcpCli.ResourceManager().AddProjectPolicyBinding(
		ctx,
		t.ProjectID(),
		roleInstanceAdmin,
		serviceAccountPrefix+saEmail,
	); err != nil {
		return deploy.Error(err)
	}

	return deploy.Done()
}

func (t *ProjectPolicy) Delete(ctx context.Context) deploy.Result {
	saEmail := t.APPBox.Status.IAM.ServiceAccountEmail
	if saEmail == "" {
		t.Logger.Info("service account is empty")
		return deploy.Done()
	}

	if err := t.gcpCli.ResourceManager().DelProjectPolicyBinding(
		ctx,
		t.ProjectID(),
		roleLoggingWriter,
		serviceAccountPrefix+saEmail,
	); err != nil {
		return deploy.Error(err)
	}

	if err := t.gcpCli.ResourceManager().DelProjectPolicyBinding(
		ctx,
		t.ProjectID(),
		roleMonitoringWriter,
		serviceAccountPrefix+saEmail,
	); err != nil {
		return deploy.Error(err)
	}

	if err := t.gcpCli.ResourceManager().DelProjectPolicyBinding(
		ctx,
		t.ProjectID(),
		roleInstanceAdmin,
		serviceAccountPrefix+saEmail,
	); err != nil {
		return deploy.Error(err)
	}
	return deploy.Done()
}
