package controller

import (
	"context"

	"github.com/tidbcloud/chaos-svc/idl/pbgen/proto/chaos"
	"github.com/tidbcloud/chaos-svc/pkg/application/cmd/backend"
	"github.com/tidbcloud/chaos-svc/pkg/application/cmd/experiment"
	backend_query "github.com/tidbcloud/chaos-svc/pkg/application/query/backend"
	"github.com/tidbcloud/chaos-svc/pkg/application/query/cluster"
	experiment_query "github.com/tidbcloud/chaos-svc/pkg/application/query/experiment"
	base "go.buf.build/protocolbuffers/go/linuxgit/tidbcloud/base"
)

type ChaosController struct {
	chaos.UnimplementedChaosServiceServer
}

func (c *ChaosController) EnableChaosBackend(ctx context.Context, req *chaos.EnableChaosBackendRequest) (*chaos.EnableChaosBackendResp, error) {
	resp := &chaos.EnableChaosBackendResp{
		BaseResp: &base.BaseResp{},
	}
	err := DiCall(func(svc *backend.EnableBackendSvc) error {
		err := svc.Execute(ctx, req)
		return err
	})
	if err != nil {
		return resp, err
	}
	return resp, nil
}

func (c *ChaosController) DisableChaosBackend(ctx context.Context, req *chaos.DisableChaosBackendRequest) (*chaos.DisableChaosBackendResp, error) {
	resp := &chaos.DisableChaosBackendResp{
		BaseResp: &base.BaseResp{},
	}
	err := DiCall(func(svc *backend.DisableBackendSvc) error {
		err := svc.Execute(ctx, req)
		return err
	})
	if err != nil {
		return resp, err
	}
	return resp, nil
}

func (c *ChaosController) GetChaosBackend(ctx context.Context, req *chaos.GetChaosBackendRequest) (*chaos.GetChaosBackendResp, error) {
	resp := &chaos.GetChaosBackendResp{
		BaseResp: &base.BaseResp{},
	}
	err := DiCall(func(svc *backend_query.GetBackendSvc) error {
		backendResp, err := svc.Execute(ctx, req)
		if err != nil {
			return err
		}
		resp.Status = backendResp.Status
		resp.Message = backendResp.Message
		resp.UpdatedAt = backendResp.UpdatedAt
		resp.UpdatedById = backendResp.UpdatedByID
		return nil
	})
	if err != nil {
		return resp, err
	}
	return resp, nil
}

func (c *ChaosController) ListExperiments(ctx context.Context, req *chaos.ListExperimentsRequest) (*chaos.ListExperimentsResp, error) {
	resp := &chaos.ListExperimentsResp{
		BaseResp: &base.BaseResp{},
	}
	err := DiCall(func(svc *experiment_query.ListExperimentSvc) error {
		experiments, total, err := svc.Execute(ctx, req)
		if err != nil {
			return err
		}
		resp.Experiments = experiments
		resp.Total = total
		return nil
	})
	if err != nil {
		return resp, err
	}
	return resp, nil
}

func (c *ChaosController) GetExperiment(ctx context.Context, req *chaos.GetExperimentRequest) (*chaos.GetExperimentResp, error) {
	resp := &chaos.GetExperimentResp{
		BaseResp: &base.BaseResp{},
	}
	err := DiCall(func(svc *experiment_query.GetExperimentSvc) error {
		experiment, err := svc.Execute(ctx, req)
		if err != nil {
			return err
		}
		resp.Experiment = experiment
		return nil
	})
	if err != nil {
		return resp, err
	}
	return resp, nil
}

func (c *ChaosController) CreateExperiment(ctx context.Context, req *chaos.CreateExperimentRequest) (*chaos.CreateExperimentResp, error) {
	resp := &chaos.CreateExperimentResp{
		BaseResp: &base.BaseResp{},
	}
	err := DiCall(func(svc *experiment.CreateExperimentSvc) error {
		experiment, err := svc.Execute(ctx, req)
		if err != nil {
			return err
		}
		resp.Experiment = experiment
		return nil
	})
	if err != nil {
		return resp, err
	}
	return resp, nil
}

func (c *ChaosController) UpdateExperiment(ctx context.Context, req *chaos.UpdateExperimentRequest) (*chaos.UpdateExperimentResp, error) {
	resp := &chaos.UpdateExperimentResp{
		BaseResp: &base.BaseResp{},
	}
	err := DiCall(func(svc *experiment.UpdateExperimentSvc) error {
		experiment, err := svc.Execute(ctx, req)
		if err != nil {
			return err
		}
		resp.Experiment = experiment
		return nil
	})
	if err != nil {
		return resp, err
	}
	return resp, nil
}

func (c *ChaosController) DeleteExperiment(ctx context.Context, req *chaos.DeleteExperimentRequest) (*chaos.DeleteExperimentResp, error) {
	resp := &chaos.DeleteExperimentResp{
		BaseResp: &base.BaseResp{},
	}
	err := DiCall(func(svc *experiment.DeleteExperimentSvc) error {
		err := svc.Execute(ctx, req)
		return err
	})
	if err != nil {
		return resp, err
	}
	return resp, nil
}

func (c *ChaosController) GetTiDBComponentTopology(ctx context.Context, req *chaos.GetTiDBComponentTopologyRequest) (*chaos.GetTiDBComponentTopologyResp, error) {
	resp := &chaos.GetTiDBComponentTopologyResp{
		BaseResp: &base.BaseResp{},
	}

	err := DiCall(func(svc *cluster.GetTiDBClusterSvc) error {
		cluster, err := svc.Execute(ctx, req)
		if err != nil {
			return err
		}
		resp.Topology = cluster
		return nil
	})
	if err != nil {
		return resp, err
	}

	return resp, nil
}
