package common

import (
	"fmt"

	"github.com/tidbcloud/dataflow-service-e2e/internal/log"
	. "github.com/tidbcloud/dataflow-service-e2e/internal/model"
	"github.com/tidbcloud/dataflow-service-e2e/internal/tidbcloud/dedicated/consoleapi"
	console_br_params "github.com/tidbcloud/dataflow-service-e2e/internal/tidbcloud/dedicated/consoleapi/br/client/backup_service"
	crrf_model "github.com/tidbcloud/dataflow-service-e2e/internal/tidbcloud/dedicated/consoleapi/crrf/model"
)

// CRRFValidator provides validation helper methods for CRRF E2E tests.
type CRRFValidator struct {
	lgr   log.SimpleLogger
	crrfW *consoleapi.CRRFClientWrapper
}

// NewCRRFValidator creates a new CRRFValidator instance.
func NewCRRFValidator(lgr log.SimpleLogger) *CRRFValidator {
	return &CRRFValidator{
		lgr:   lgr,
		crrfW: consoleapi.NewCRRFClientWrapper(lgr),
	}
}

// Client returns the underlying CRRFClientWrapper for direct API access.
func (v *CRRFValidator) Client() *consoleapi.CRRFClientWrapper {
	return v.crrfW
}

// Enable enables CRRF for a cluster and returns the response.
func (v *CRRFValidator) Enable(cluster *TiDBDedicatedEntity, secondaryRegion string) error {
	_, err := v.crrfW.EnableCRRF(cluster, secondaryRegion)
	return err
}

// Query queries CRRF status and returns the response.
func (v *CRRFValidator) Query(cluster *TiDBDedicatedEntity) (*crrf_model.DataflowQueryCRRFResponse, error) {
	return v.crrfW.QueryCRRF(cluster)
}

// Disable disables CRRF for a cluster.
func (v *CRRFValidator) Disable(cluster *TiDBDedicatedEntity) error {
	_, err := v.crrfW.DisableCRRF(cluster)
	return err
}

// DisableIfEnabled disables CRRF for a cluster, tolerating cases where CRRF was never enabled
// or is already disabled (HTTP 403/404). Use this for cleanup in defers.
func (v *CRRFValidator) DisableIfEnabled(cluster *TiDBDedicatedEntity) error {
	return v.crrfW.DisableCRRFIfEnabled(cluster)
}

// ExpectStatus checks that CRRF has the expected status.
func (v *CRRFValidator) ExpectStatus(cluster *TiDBDedicatedEntity, expectedStatus crrf_model.DataflowCRRFStatus) error {
	resp, err := v.crrfW.QueryCRRF(cluster)
	if err != nil {
		return fmt.Errorf("query CRRF: %w", err)
	}
	if resp.Status == nil || *resp.Status != expectedStatus {
		got := "<nil>"
		if resp.Status != nil {
			got = string(*resp.Status)
		}
		return fmt.Errorf("expected CRRF status %q, got %q", expectedStatus, got)
	}
	v.lgr.Info("CRRF status is %s as expected", expectedStatus)
	return nil
}

// ExpectDisabledOrNotFound checks CRRF is in disabled state (or not yet created).
func (v *CRRFValidator) ExpectDisabledOrNotFound(cluster *TiDBDedicatedEntity) error {
	resp, err := v.crrfW.QueryCRRF(cluster)
	if err != nil {
		// If query fails (e.g., 404), CRRF is not configured — that's acceptable
		v.lgr.Info("CRRF query returned error (likely not configured): %s", err.Error())
		return nil
	}
	if resp.Status == nil || *resp.Status == crrf_model.DataflowCRRFStatusCRRFSTATUSDISABLED {
		v.lgr.Info("CRRF is disabled or not configured as expected")
		return nil
	}
	return fmt.Errorf("expected CRRF disabled or not found, got status %q", *resp.Status)
}

// GetSecondaryRegion returns a valid secondary region for the given cluster by calling GetBackupOptions
// via the BackupService console API (/api/v1/orgs/.../backups/options).
// It picks the first available dual-region option returned by the API.
func (v *CRRFValidator) GetSecondaryRegion(cluster *TiDBDedicatedEntity) (string, error) {
	params := console_br_params.NewGetBackupOptionsParams().
		WithOrgID(cluster.OrgID).
		WithProjectID(cluster.ProjectID).
		WithClusterID(cluster.ClusterID)

	resp, err := consoleapi.BrBackupServiceClient().GetBackupOptions(params, nil)
	if err != nil {
		return "", fmt.Errorf("GetBackupOptions: %w", err)
	}

	if resp.Payload.DualRegionOptions == nil {
		return "", fmt.Errorf("no dual_region_options in GetBackupOptions response for cluster %s", cluster.ClusterID)
	}

	opts := resp.Payload.DualRegionOptions.RegionOptions
	if len(opts) == 0 {
		return "", fmt.Errorf("no secondary region options available for cluster %s (region=%s)", cluster.ClusterID, cluster.Region)
	}

	if opts[0].Region == nil || opts[0].Region.Name == "" {
		return "", fmt.Errorf("secondary region name is empty in GetBackupOptions response")
	}

	secondaryRegion := opts[0].Region.Name
	v.lgr.Info("selected secondary region %q for cluster %s (from %d options)", secondaryRegion, cluster.ClusterID, len(opts))
	return secondaryRegion, nil
}
