package dbaasui

import (
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"
)

const (
	ReadinessAPIVersion = "cp9.tidbcloud.com/v1alpha1"
	ReadinessKind       = "DbaasUIReadiness"
)

const imageRepositoryPrefix = "385595570414.dkr.ecr.us-west-2.amazonaws.com/tidbcloud/cp9-dbaas-ui@sha256:"

// ValidateImageReference accepts only the central account-414 repository at
// an exact SHA-256 digest. Candidate tags and pending promotion sentinels are
// never runtime-ready image references.
func ValidateImageReference(image string) error {
	image = strings.TrimSpace(image)
	if !strings.HasPrefix(image, imageRepositoryPrefix) {
		return fmt.Errorf("dbaas-ui image %q is not an immutable account-414 SHA-256 digest", image)
	}
	digest := strings.TrimPrefix(image, imageRepositoryPrefix)
	if len(digest) != sha256.Size*2 || strings.Contains(digest, "pending") {
		return fmt.Errorf("dbaas-ui image %q is not an immutable account-414 SHA-256 digest", image)
	}
	if _, err := hex.DecodeString(digest); err != nil {
		return fmt.Errorf("dbaas-ui image %q has an invalid SHA-256 digest: %w", image, err)
	}
	return nil
}

// ReadinessEvidence separates CP9-owned delivery from shared Auth0/identity
// dependencies. Shared drift degrades the browser login without failing the
// otherwise healthy Remote session.
type ReadinessEvidence struct {
	APIVersion string `json:"api_version"`
	Kind       string `json:"kind"`
	Status     string `json:"status"`
	URL        string `json:"url,omitempty"`
	Image      string `json:"image,omitempty"`

	UIStaticReady     bool `json:"ui_static_ready"`
	UIAuthReady       bool `json:"ui_auth_ready"`
	UIIdentityReady   bool `json:"ui_identity_ready"`
	SessionOwnedReady bool `json:"session_owned_ready"`
	UIReady           bool `json:"ui_ready"`

	StaticMessage   string `json:"static_message,omitempty"`
	AuthMessage     string `json:"auth_message,omitempty"`
	IdentityMessage string `json:"identity_message,omitempty"`

	UpdatedAt time.Time `json:"updated_at"`
}

// Recompute derives the two aggregate states from their independently
// inspectable dimensions.
func (e *ReadinessEvidence) Recompute() {
	if e == nil {
		return
	}
	if e.APIVersion == "" {
		e.APIVersion = ReadinessAPIVersion
	}
	if e.Kind == "" {
		e.Kind = ReadinessKind
	}
	e.SessionOwnedReady = e.UIStaticReady
	e.UIReady = e.SessionOwnedReady && e.UIAuthReady && e.UIIdentityReady
	switch {
	case e.UIReady:
		e.Status = "ready"
	case e.SessionOwnedReady:
		e.Status = "degraded"
	default:
		e.Status = "not_ready"
	}
}

func ReadinessPath(stateDir string) string {
	return filepath.Join(stateDir, "tilt", "reports", "evidence", "dbaas-ui-readiness.json")
}

// SaveReadiness writes a credential-free evidence document atomically.
func SaveReadiness(stateDir string, evidence *ReadinessEvidence) error {
	if evidence == nil {
		return fmt.Errorf("dbaas-ui readiness evidence is nil")
	}
	evidence.Recompute()
	if evidence.UpdatedAt.IsZero() {
		evidence.UpdatedAt = time.Now().UTC()
	}
	data, err := json.MarshalIndent(evidence, "", "  ")
	if err != nil {
		return fmt.Errorf("marshal dbaas-ui readiness evidence: %w", err)
	}
	data = append(data, '\n')
	path := ReadinessPath(stateDir)
	if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
		return fmt.Errorf("create dbaas-ui readiness evidence directory: %w", err)
	}
	temporary, err := os.CreateTemp(filepath.Dir(path), ".dbaas-ui-readiness-*.tmp")
	if err != nil {
		return fmt.Errorf("create dbaas-ui readiness temporary file: %w", err)
	}
	temporaryPath := temporary.Name()
	defer os.Remove(temporaryPath)
	if err := temporary.Chmod(0o600); err != nil {
		_ = temporary.Close()
		return fmt.Errorf("set dbaas-ui readiness temporary file mode: %w", err)
	}
	if _, err := temporary.Write(data); err != nil {
		_ = temporary.Close()
		return fmt.Errorf("write dbaas-ui readiness temporary file: %w", err)
	}
	if err := temporary.Close(); err != nil {
		return fmt.Errorf("close dbaas-ui readiness temporary file: %w", err)
	}
	if err := os.Rename(temporaryPath, path); err != nil {
		return fmt.Errorf("replace dbaas-ui readiness evidence: %w", err)
	}
	return nil
}
